Section 5.6 ボタン用レイヤのカスタマイズ(その1)

前回予告した通り、今回はボタン用レイヤをカスタマイズしてみるね。
機能を追加したりするって言ってたよね?
具体的にはどんなことするの?
今回やるのはこの4つ。

<追加・変更する機能>

  1. ボタンが操作できない時(enabled プロパティが false の時)に表示する画像を追加する
  2. ボタンを押した時に効果音を再生する
  3. ボタンの上にマウスカーソルが乗った時に効果音を再生する
  4. ボタンの上からマウスカーソルが出て行った時に効果音を再生する

ボタンが操作できない時に表示する画像を追加するっていうのは、ボタン用の画像を4種類にするってこと?
うん。今までは普通の状態用、マウスカーソルが上に乗ってる時用、ボタンが押されてる時用の3種類だったけど、 これにボタンが使えない時用の画像を追加するの。
あと、効果音っていうのは button タグの clickse 属性と enterse 属性と leavese 属性で設定できる効果音のこと?
そ。それをシステムボタンでもできるようにしようってこと。
でもそれって元々ついてる機能なんじゃないの?
ううん。ButtonLayer クラスにも SystemButtonLayer クラスにも効果音を再生する機能はついてないよ。
えっ、そうなの?
うん。button タグで作ったボタンの効果音の再生はメッセージレイヤが管理してるんだ。
だから効果音を再生するスクリプトは ButtonLayer クラスの定義の中じゃなくて、 MessageLayer クラスの定義の中に書いてあるの。
ふぅん、そうなんだ。
あと、今回作るボタンは SystemButtonLayer クラスを継承して作ることにするね。
SystemButtonLayer クラスって、 §5.2 でボタンを作った時に使ったクラスだよね?
そうそう、それ。
そういえば、SystemButtonLayer クラスってちゃんと説明してもらってないよね?
あー、確かに§5.2 でボタンを作った時は loadImages メソッドしか使ってなかったね。
しかも loadImages メソッドって ButtonLayer クラスのを使ってるから、 そのまま ButtonLayer クラスの方に移っちゃったよね。
じゃあ、まず SystemButtonLayer クラスから見とこっか。
うん、そうだね。
って言っても、SystemButtonLayer クラスって、 そんなにたくさん機能が追加されてるわけじゃないんだけどね。

SystemButtonLayer クラス(systembutton.ks の中で定義)>

class SystemButtonLayer extends ButtonLayer
    // クリックされたときに実行する関数を指定できるボタンレイヤ
{
    var onClickFunction;

    function SystemButtonLayer(window, parent, func)
    {
        super.ButtonLayer(window, parent);
        focusable = false;
        visible = true;
        onClickFunction = func;
    }

    function finalize()
    {
        super.finalize(...);
    }

    function onClick()
    {
        super.onClick(...);
    }

    function onMouseUp(x, y, button, shift)
    {
        if(enabled && button == mbLeft)
            onClickFunction(this);
        super.onMouseUp(...);
    }

}

まずはいつものようにコンストラクタから見ていくね。
focusable っていうのはプロパティだよね?
うん。focusable プロパティを true にするとフォーカスを受け取れるんだけど、 前にも言ったように、今回はフォーカスを設定しないから、このプロパティはずっと false のまま。
あと、visible はレイヤを表示するかどうかのプロパティだよね。
そ。true にしてるってことは、表示状態にしてるってことだね。
onClickFunction っていうのは、メンバ変数だよね?
これってどんなメンバ変数なの?
SystemButtonLayer クラスの第3引数って何だったか覚えてる?
え〜っと…ボタンが押された時に実行するメソッド、だったっけ?
そうそう。§5.2inform メソッドを呼び出す式中関数を第3引数に指定したよね。
onClickFunction は第3引数に指定されてる関数の参照を保存しとくためのメンバ変数だよ。
※関数の参照については §1.19 参照
だから func の値を onClickFunction に代入してるんだね。
じゃあ、これでコンストラクタは OK だね。
デストラクタonClick メソッド はスーパークラスのメソッドを呼び出してるだけだから、 次は onMouseUp メソッド ね。
if の条件式はどうなってるか解る?
enabled && button == mbLeft になってるから…
ボタンが使える状態で、あとボタンが mbLeft だから、左のボタンっていうことかな?
ん、そういうこと。
ボタンが使える状態で、マウスの左ボタンが押された後離された時に onClickFunction を呼び出すってことね。
引数が this になってるけど…
確か this ってこのクラスのオブジェクトっていう意味だったよね?
うん。this を引数にすることで、 呼び出すメソッド(onClickFunction)にこのボタンへの参照を渡してるんだ。
なんでそんなことしてるの?
action メソッドみたいに、色んなイベント処理をするメソッドを使えるようにするため、かな。
どういうこと?
action メソッドの引数は辞書配列になってて、 target っていう要素にイベントが起こったオブジェクトへの参照がセットされてたでしょ。
うん。§3.8 でやったよね。
onClickFunction を呼び出す時引数に this を指定するってことは、 action メソッドでいうところの ev.target を引数に指定してるのと同じってことだからね。
そっか。引数を調べればどのボタンが押されたのか判るっていうことなんだね。
そういうこと。
さて、これで SystemButtonLayer クラスも一通り見たから、ここから機能を拡張していくね。
は〜い。
SystemButtonLayer クラスを継承して、 機能を拡張した ExSystemButtonLayer クラスを作ることにするね。
まず、コンストラクタとデストラクタはこんな感じ。

ExSystemButtonLayer クラスのコンストラクタとデストラクタ>

class ExSystemButtonLayer extends SystemButtonLayer
{
    // コンストラクタ
    function ExSystemButtonLayer(window, parent, func)
    {
        super.SystemButtonLayer(window, parent, func);
    }

    // デストラクタ
    function finalize()
    {
        super.finalize();
    }
}

これってスーパークラスのコンストラクタとデストラクタを呼び出してるだけ…だよね?
うん。コンストラクタとデストラクタでは特に何もやることないから。
そうなんだ。
じゃあ、コンストラクタの引数も SystemButtonLayer クラスと同じなの?
うん、3つとも同じだよ。
じゃ、次はボタンが操作できない時に表示する画像を追加する機能を作っていくね。
これが今回使うボタン用の画像。

ExSystemButtonLayer クラスで使うボタン用画像>

ボタン用画像

右端の×が付いてるのがボタンが操作できない時に表示する画像なんだよね?
そうだよ。左から3つ目までは前と同じで、一番右にあるのがボタンが使えない時用の画像。

今回使うボタン用画像

ボタンが操作できない時に右端の画像を表示するためには、 SystemButtonLayer クラスのどのメソッドをオーバーライドすればいいと思う?
え? ん〜っと、ボタンの表示を切り替えてるのは drawState メソッド だから、 これはオーバーライドしないといけないよね?
ん、そうだね。
あともう1つオーバーライドしなくちゃいけないメソッドがあるんだけど、どのメソッドかわかる?
え、まだあるの?
今回はボタンの画像が4種類あるわけだから、レイヤの表示幅を画像の幅の4分の1にしなくちゃいけないでしょ?
あ、そっか。
ってことは、レイヤの表示サイズを設定してたのって loadImages メソッド だったから、 これもオーバーライドしなくちゃいけないってこと?
うん、そういうこと。
じゃまず loadImages メソッドをオーバーライドするね。

ExSystemButtonLayer クラスの loadImages メソッド>

// ボタン用画像を読み込みます
function loadImages(storage, key)
{
    // スーパークラス(SystemButtonLayerクラス)の loadImages メソッドを呼び出します
    super.loadImages(storage, key);

    // レイヤの表示幅をボタン画像の4分の1に設定します
    global.Layer.width = imageWidth \ 4;
}

えっと、スーパークラスの loadImages メソッドを呼び出してるのは解るんだけど、 レイヤの表示幅を設定してるところの『global.Layer.width』ってどういうこと?
ん〜、そこがちょっとややこしいところなんだけどね…
ButtonLayer クラスの loadImages メソッド で、 レイヤの表示幅を設定するのに『super.width』を使ってたでしょ。
確か、ButtonLayer クラスは width プロパティをオーバーライドしてるからこうしなくちゃいけない、とか言ってたよね?
そうそう。
で、ExSystemButtonLayer クラスは SystemButtonLayer クラスを継承して作ってるから、 スーパークラスのさらにスーパークラスの width メソッドを使いたいわけね。
じゃあ『super.super.width』でいいんじゃないの?
それがそういう書き方はできないんだ。
そうなの?
うん。そういう時は『global.クラス名.プロパティ名』っていうふうに書くことになってるの。
で、ExSystemButtonLayer クラスのスーパークラスのさらにスーパークラスは Layer クラスだから…
global.Layer.width』になるってこと?
そういうこと。
なんか複雑だね…
まぁね。でもスーパークラスのさらにスーパークラスのメソッドとかプロパティを使うことってそんなに無いと思うから、 こんな書き方があるってことを頭の片隅に置いとくくらいで十分だよ。
うん、わかった。
それじゃ次は drawState メソッドだね。

ExSystemButtonLayer クラスの drawState メソッド>

function drawState(s)
{
    // 状態 s に対応する画像を描画
    // s :  0 : 普通の状態
    //      1 : ボタンが押された状態
    //      2 : ボタンの上にマウスカーソルがある状態
    if(!enabled)
    {
        s = 3; // 無効状態
    }

    if(Butt_imageLoaded)
    {
        // ボタンの画像を設定(左から(s+1)番目の画像を表示)します
        imageLeft = -s * width;
    }
}

ButtonLayer クラスの drawState メソッド は、 enabledfalse の時 s0 にしてたけど、 今回はボタンが使えない時に左から4番目の画像を表示するから、s3 になってるんだよね?
ん、そういうこと。
drawState メソッドはここしか変わってないから簡単でしょ?
うん、そうだね。
これでボタン画像の方はできたから次は効果音なんだけど、 結構長くなっちゃったから、今回はここまでにしとこっか。
じゃあ、効果音を再生する機能は次回作るの?
うん、次回で ExSystemButtonLayer クラスを完成させるから。
それじゃ、また次回ね!


前へ | TOP | 次へ