Section 5.5 ボタン用レイヤ(その3)

今回は ButtonLayer クラスのイベントハンドラを見ていこうと思うんだけど、 その前に§5.3で説明しなかった callOnPaint プロパティから説明するね。
あ、そういえばそんなプロパティがあったっけ。
callOnPaintLayer クラスのプロパティで、 この値を true にすると、次に画面が描画される直前に onPaint っていうメソッドが呼び出されるんだ。
え〜っと…それってどういうことなの?
例えば、背景レイヤに画像を読み込んだら、ウィンドウに新しい背景の画像が表示されるでしょ。
うん、そだね。
画面を描画するっていうのは、新しい背景を表示するために、ウィンドウに表示されてる画像を更新することだよ。
へぇ、そういうのを画面を描画するって言うんだ。
実際には、背景だけじゃなくて、前景レイヤの画像を変えたり、あとレイヤの位置を変えたり、 表示状態を変えたり、ウィンドウを最小化した後元に戻したり、 とにかくウィンドウに表示されてる画像が変化した時に画面が描画されるんだ。
あ、そうなんだ。
で、callOnPaint プロパティを true に設定しとくと、 その後画面を描画する直前に onPaint っていうイベントハンドラが呼び出されるんだ。
う〜ん、何となくわかったような気はするんだけど、 具体的には onPaint メソッドってどうやって使うものなの?
じゃあ、まずは ButtonLayer クラスの onPaint メソッドを見てみよっか。
うん、そうだね。

ButtonLayer クラスの onPaint メソッド(175行目付近)>

function onPaint()
{
    // 描画の直前に呼ばれる
    super.onPaint(...);
    draw();
}

これが ButtonLayer クラスの onPaint メソッドだよ。
結構シンプルだね。
うん。スーパークラスの onPaint メソッドを呼び出した後に、 draw メソッドを呼び出してるだけだよ。
draw メソッドってまだ見てないよね?
これが draw メソッドだよ。

ButtonLayer クラスの draw メソッド(166行目付近)>

function draw()
{
    // 現在の状態にあわせて描画を行う
    if(Butt_mouseDown) drawState(1);
    else if(Butt_mouseOn) drawState(2);
    else if(Butt_showFocusImage && focused) drawState(3);
    else drawState(0);
}

あ、draw メソッドって、drawState メソッド を呼び出してるんだ。
そ。つまり、draw メソッドを呼び出すと、 今のボタンの状態に応じてボタンの画像が更新されるってワケ。
なんか if の条件にいろんな変数が出てきてるけど、これってメンバ変数だよね?
そうだよ。Butt_mouseDown がマウスのボタンが押されてる間 true になってるメンバ変数で、 Butt_mouseOn がマウスカーソルがボタンの上にある間 true になってるメンバ変数だよ。
確か、Butt_showFocusImage っていうメンバ変数は今回はずっと false なんだったよね?
うん。だから drawState(3); は実行されないよ。
ってことは… drawState メソッドの引数は Butt_mouseDowntrue の時 1 で、 Butt_mouseOntrue の時 2 で、 それ以外の時は 0 になるってことだね。
引数が 2 になるのは、Butt_mouseOntrue で、 さらに Butt_mouseDownfalse の時ね。
あ、そっか。else if だもんね。
つまり、マウスカーソルがボタンの上にあって、さらにボタンが押されてる時は、 ボタンが押されてる時の画像の方が表示される、ってこと。
まぁ普通ボタンが押されてる時はマウスカーソルがボタンの上にあるから、 こうしとかないとボタンが押されてる時の画像が表示されなくなっちゃうからね。
なるほど、確かにそうだね。
どう? ちゃんと drawState メソッドの引数とボタンの状態が対応してるでしょ。
うん、そうだね。
じゃあ、ここからは ButtonLayer クラスのイベントハンドラを見ていくね。
onPaint メソッドはもう出てきたよね。
だね。
システムボタンを作るときに重要なイベントハンドラはこんなところかな。

ButtonLayer クラスの主なイベントハンドラ>
メソッド名イベント
onMouseDownマウスのボタンが押された
onMouseUpマウスのボタンが離された
onMouseEnterマウスカーソルが入ってきた
onMouseLeaveマウスカーソルが出ていった
onNodeDisabledレイヤが操作不能になった
onNodeEnabledレイヤが操作可能になった
onPaint画面が描画される

なんか見たことないイベントハンドラもあるね。
とりあえず1つずつ見ていこっか。
そうだね。
じゃあまずは onMouseDown メソッドから。

onMouseDown メソッド(143行目付近)>

function onMouseDown()
{
    // onMouseDown イベントハンドラ
    Butt_mouseDown = true;
    focus();
    update();
    super.onMouseDown(...);
}

Butt_mouseDown って draw メソッド のところで出てきたメンバ変数だよね。
マウスのボタンが押されてるかどうかを表すメンバ変数だね。
onMouseDown メソッドはマウスのボタンが押された時に呼び出されるから、 Butt_mouseDowntrue にしてるんだね。
ん、そういうこと。
その次の focus っていうメソッドは?
focus メソッドはこのレイヤにフォーカスを設定するメソッドなんだけど、 §5.3 で言った通り、今回はボタンがフォーカスを受け取れるようにしないから、 このメソッドは無視しちゃって OK。
あ、そうなんだ。
じゃあ update っていうのは?
update メソッドは、 callOnPaint プロパティを true にして、 画面を強制的に描画するメソッドだよ。
強制的に描画って…?
本来画面の描画って、ウィンドウ内部の画像が変わったときだけ実行されるんだけど、 update メソッドを実行すると、ウィンドウ内部の画像が変わってなくても画面が再描画されるんだ。
なんでそんなことするの?
ボタンの画像を更新するのが drawState メソッド で、 drawState メソッドを呼び出すのが draw メソッド で、 draw メソッドを呼び出すのが onPaint メソッド だったでしょ?
えっ? え〜っと……
う、うん、そうだったよね。
ちゃんと覚えてた?
うん、だいじょぶ…だと思う。
まぁこの辺はちょっとややこしいからね。
で、onPaint メソッド は、画面が描画される時に callOnPaint プロパティが true になってれば呼び出されるわけだから、 ボタンの画像を更新したい場合は、update メソッドを呼び出す必要があるワケ。
えっとぉ…もう一回説明してもらってもいいかな…?
OK。じゃあ今度はフローチャートにしてみるね。

<マウスのボタンが押された時の処理の流れ>

処理の流れのフローチャート

マウスのボタンが押されてからボタンの画像が更新されるまでの流れは大体こんな感じだよ。
う〜ん、やっぱりややこしいね…
マウスのボタンが押されると onMouseDown メソッドが呼び出されて、 Butt_mouseDowntrue になるところまでは大丈夫だよね?
うん、そこまでは解るよ。
もしこの後 update メソッドを呼び出さなかったら、 画面を更新する必要がないから onPaint メソッドは呼び出されないんだ。
えっ、そうなの?
うん。だってレイヤってイベントハンドラを書き換えたりオーバーライドしたりしない限りは、 クリックしても何も起こらないからね。
あ、そうなんだ。
何も起こらないってことはウィンドウ内部の画像も変わらないってことだから、 画面を描画する必要がないってこと。
だから onPaint メソッドが呼び出されないってこと?
そ。でもそれじゃボタンの画像が変えられないから、画面を描画するために update メソッドを呼び出して、強制的に画面を描画するってワケ。
なるほどねぇ…
あ、でも、それだったら onMouseDown メソッドの中で draw メソッドを呼び出せばいいんじゃない?
確かに、そうすれば update メソッドは呼び出さなくても良くなるよ。
でしょ?
でもね、onPaint メソッド以外のイベントハンドラの中では、 直接画像を更新する処理はしない方がいいんだ。
えっ、どうして?
まぁ、今回の場合は画像を更新する処理が単純だから onMouseDown メソッドの中で直接 draw メソッドを呼び出しても特に問題はないんだけど…
だけど…?
画像を更新する処理が複雑で時間がかかる場合は、 onPaint メソッド以外のイベントハンドラの中で直接画像を更新する処理を実行すると、 例えばボタンを連打して onMouseDown イベントをたくさん発生させた時とかに、 処理しないといけないイベントがいっぱい溜まっちゃってフリーズしたみたいになっちゃう可能性があるんだ。
へぇ、そうなんだ。
じゃあ onPaint メソッドで画像を更新すると大丈夫なの?
うん。詳しい説明は省略するけど、update メソッドと onPaint メソッドを使うと、 処理しないといけないイベントが溜まり過ぎないようにちゃんと制御してくれるからね。
ふぅん…でもなんか難しい話だね。
あー、別に難しく考えなくても、画像を更新する処理は onPaint メソッドの中で実行した方が安全って思っててくれればいいよ。
特に、画像を更新する処理が複雑な場合はね。
うん、わかった。
それじゃ、残りのイベントハンドラを見ていこ。
はーい。
次は onMouseUp メソッドだね。

onMouseUp メソッド(152行目付近)>

function onMouseUp()
{
    // onMouseUp イベントハンドラ
    Butt_mouseDown = false;
    update();
    super.onMouseUp(...);
}

これは onMouseDown メソッド と似てるからわかるよね?
onMouseDown メソッド の時は Butt_mouseDowntrue にしてたけど、 onMouseUp メソッドはボタンが離された時に呼び出されるから、 Butt_mouseDownfalse にしてるんだよね。
ん、そういうこと。
それじゃ次は onMouseEnter メソッドね。

onMouseEnter メソッド(182行目付近)>

function onMouseEnter()
{
    // マウスがレイヤ領域内に入った
    update();
    Butt_mouseOn = true;
    super.onMouseEnter(...);
}

onMouseEnter メソッドは、マウスカーソルがレイヤの領域内に入った時、 つまりボタンの上にマウスカーソルが乗った時に呼び出されるメソッドなんだけど、 値を設定してるメンバ変数が違ってるだけで、他は onMouseUp メソッド とかと似てるでしょ。
Butt_mouseOntrue にしてるね。
これってマウスカーソルがボタンの上に乗ってる時に true になるんだったよね?
ん、そう。
だから、マウスカーソルがレイヤの領域内から出ていった時に呼び出される onMouseLeave メソッドだと…

onMouseLeave メソッド(190行目付近)>

function onMouseLeave()
{
    // マウスがレイヤ領域から出ていった
    update();
    Butt_mouseOn = false;
    Butt_mouseDown = false;
    super.onMouseLeave(...);
}

onMouseEnter メソッド の時と逆に、 Butt_mouseOnfalse にしてるんだね。
うん。あと、マウスカーソルがボタンの上から離れるとボタンを押せなくなるから、 Butt_mouseDownfalse になるわけね。
なるほどね。
あ、ちょっと聞きたいことがあるんだけど。
ん? 何?
onMouseEnter メソッドと onMouseLeave メソッドって、 メンバ変数の値を設定する前に update メソッドを呼び出してるけど、 onPaint メソッドって、メンバ変数を更新した後に呼び出さなくちゃいけないんじゃないの?
なるほど、よくそこに気付いたね。
うん、何となく気になっちゃって。
結論から言うと、update メソッドはイベントハンドラのどこで呼び出してもいいんだ。
え、そうなの? なんで?
update メソッドは、システムに対して画面を再描画してっていう要求を出すだけで、 実際に画面を描画してるわけじゃないんだ。
だから、実際に画面が描画されるのはイベントハンドラの実行が終わった後になるの。
へぇ、そうなんだ…
あ、だから update メソッドをどこで実行しても、 画面が描画される時にはメンバ変数の値は更新されてるんだね。
そういうこと。
これで大体のことはわかった?
うん、おっけー。
じゃ、次は onNodeDisabled メソッドだね。

onNodeDisabled メソッド(199行目付近)>

function onNodeDisabled()
{
    // レイヤのノードが不可になった
    super.onNodeDisabled(...);
    Butt_mouseDown = false;
    update();
}

これって初めて見るメソッドだけど、どんな時に呼び出されるの?
onNodeDisabled メソッドは、レイヤの enabled プロパティが false になった時に呼び出されるんだ。
あと、親レイヤの enabledfalse になると、 このレイヤの操作もできなくなるから、その時にも呼び出されるよ。
えっと、確か enabled プロパティが false の時って、 drawState メソッドs0 になるんだったよね?
ん。つまり、このメソッドが呼び出されると、ボタンの表示は通常の状態になるわけね。
だね。
で、これと逆のメソッドが onNodeEnabled メソッド。

onNodeEnabled メソッド(207行目付近)>

function onNodeEnabled()
{
    // レイヤのノードが有効になった
    super.onNodeEnabled(...);
    update();
}

さっきと逆ってことは、onNodeEnabled メソッドはレイヤの enabledtrue になった時に呼び出されるってこと?
そ。あと、親レイヤの enabledtrue になった結果、 レイヤが操作可能になった時にも呼び出されるんだけどね。
このメソッドって update メソッドを呼び出してるだけで、 メンバ変数の値は変えてないみたいだけど…?
まぁ、レイヤが操作可能になっただけで、ボタンが押されたわけでも、マウスカーソルが乗ったわけでもないからね。
メンバ変数は変えなくてもいいでしょ。
あ、そう言われればそうだね。
onPaint メソッド は最初にやったから、 これで一通りイベントハンドラを見てこれたね。
イベントハンドラ自体はどれも結構シンプルだったね。
基本的にはメンバ変数を設定して update メソッドを呼び出すだけだからね。
そうだね。
それじゃ、これでボタン用レイヤの説明はとりあえずおしまい。
次回はボタン用レイヤをカスタマイズしてみるね。
カスタマイズって?
ちょっと機能を追加したりとかね。
ボタン用レイヤって結構複雑だから、機能を追加したりするのって大変なんじゃない?
ううん。スクリプトの一部を変えるだけだから、ここまでで見てきた内容が解ればそんなに難しくないよ。
ふぅん、そうなの?
うん。
それじゃ、また次回ね!


前へ | TOP | 次へ