10.15 メッセージ履歴のカスタマイズ 〜背景画像の表示〜(その2)

今回もメッセージ履歴画面に背景画像を表示するためにオーバーライドするメソッドとか新しく作るメソッドを見てくね。
はーい。
じゃまずは drawText メソッドからね。
drawText メソッドについては §3.4 参照。
drawText メソッドってレイヤに文字を書き込むメソッドだよね?
うん。
drawText メソッドはメッセージ履歴レイヤ(HistoryLayer)クラスに元々あるメソッドだから、 それをオーバーライドしてるわけだけど、 なんで drawText メソッドをオーバーライドしなくちゃいけないかわかる?
う〜ん…メッセージ履歴画面に背景画像を表示する時は、メッセージ履歴レイヤじゃなくて新しく作ったレイヤの方に履歴メッセージを書き込むからかなぁ?
まぁそういうことだね。
普通はメッセージ履歴レイヤに履歴メッセージを書き込むようになってるけど、 背景画像を表示する場合は、新しく作ったレイヤ(messageLayer)に履歴メッセージを書き込むように変えなきゃいけないよね。
そっか。確かにそーだね。
ってワケだから、drawText メソッドはこんなふうにオーバーライドするよ。

ExtendedHistoryLayer クラスの drawText メソッド>

function drawText()
{
    // 背景に画像を表示しているときはメッセージ履歴表示用レイヤ(messageLayer)に
    // 表示していないときは本来のメッセージ履歴レイヤ(this)に書き込みます
    if(messageLayer !== void)
        messageLayer.drawText(...);
    else
        super.drawText(...);
}

そんなに複雑じゃないから、何やってるかは大体わかるでしょ?
messageLayervoid じゃなかったら messageLayerdrawText メソッドを呼び出してて、 messageLayervoid だったらスーパークラスの drawText メソッドを呼び出してるね。
つまり、メッセージ履歴画面に背景画像を表示する設定にしてたら messageLayer が作られてる(messageLayervoid じゃない)から、 messageLayer の方に履歴メッセージを書き込んで、 普通のメッセージ履歴画面にしてたら、スーパークラス(HistoryLayer クラス)の drawText メソッドを呼び出して、メッセージ履歴レイヤに履歴メッセージを書き込むわけね。
要するに、履歴メッセージ表示用のレイヤ(messageLayer)があるかどうかで、 メッセージを書き込むレイヤを変えてるってことだよね?
ん、そういうこと。
えっと、ちょっと気になることがあるんだけど…
ん?
drawText メソッドって引数がいっぱいあったよね?
けどオーバーライドした drawText メソッドには引数がないよ?
あー、それなら別に問題ないよ。
えっ、じゃあオーバーライドした drawText メソッドを呼び出す時は引数がいらないってこと?
いや、そーじゃなくって…
messageLayerdrawText メソッドとかスーパークラスの drawText メソッドを呼び出す時、引数に “...” って書いてるでしょ。
引数に “...” って書くと、 ExtendedHistoryLayer クラスの drawText メソッドを呼び出した時に指定されてた引数がそのまま messageLayerdrawText メソッドとかスーパークラスの drawText メソッドの引数になるんだよね?
※引数の省略については §1.17 参照。
そうそう。
で、メソッドの中で “...” を引数に指定して他のメソッドを呼び出す場合は、 そのメソッドには仮引数を書かなくてもいいんだ。
ちなみに仮引数ってのは “function drawText” の後のカッコの中に書く引数のことね。
※メソッドを定義する時にメソッド名に続く括弧の中に指定する引数を仮引数と呼び、 メソッドを呼び出すときに指定する引数を実引数と呼びます。例えば、“function sum(x, y){return x + y;}” の xy は仮引数であり、“var a = sum(n, 1);” の n1 は実引数です。
どういうこと?
つまり、この drawText メソッドは、 こんなふうに仮引数を全部ちゃんと書いてる時と同じ動作をするってことだよ。

これと等価な drawText メソッド>

function drawText(x, y, text, color, opa, aa, shadowlevel, shadowcolor, shadowwidth, shadowofsx, shadowofsy)
{
    // 背景に画像を表示しているときはメッセージ履歴表示用レイヤ(messageLayer)に
    // 表示していないときは本来のメッセージ履歴レイヤ(this)に書き込みます
    if(messageLayer !== void)
        messageLayer.drawText(...);
    else
        super.drawText(...);
}

だから、x とか y とかの仮引数を使わずに、 “...” だけを使ってメソッドを呼び出す場合は、仮引数を省略して “function drawText()” って書いてもいいってことね。
へぇ、そーなんだ。
あとはいいかな?
うん。
じゃ次は fillRect メソッドね。
fillRect メソッドについては §3.2 参照。
fillRect メソッドって、確か元々書いてあった履歴メッセージを消すのに使うんだよね?
§10.6 参照。
そ。だからこれも drawText メソッドと同じで、 履歴メッセージ表示用のレイヤ(messageLayer)があるかどうかで場合分けをしなきゃいけないの。
そっか。
って言っても、やり方は drawText メソッドの時と全く同じだよ。

ExtendedHistoryLayer クラスの fillRect メソッド>

function fillRect()
{
    // 背景に画像を表示しているときはメッセージ履歴表示用レイヤ(messageLayer)を
    // 表示していないときは本来のメッセージ履歴レイヤ(this)を塗りつぶします
    if(messageLayer !== void)
        messageLayer.fillRect(...);
    else
        super.fillRect(...);
}

確かに“drawText”が“fillRect”に置き換わってるだけみたいだね。
fillRect メソッドは特に問題ないよね?
うん。
んじゃ次は copyRect メソッドね。

ExtendedHistoryLayer クラスの copyRect メソッド>

function copyRect(dleft, dtop, src, sleft, stop, swidth, sheight)
{
    // 背景に画像を表示しているときはメッセージ履歴表示用レイヤ(messageLayer)の内容を
    // 表示していないときは本来のメッセージ履歴レイヤ(this)の内容をコピーします
    if(messageLayer !== void)
        messageLayer.copyRect(dleft, dtop, messageLayer, sleft, stop, swidth, sheight);
    else
        super.copyRect(...);
}

これも基本的に drawText メソッドや fillRect メソッドとおんなじなんだけど…
messageLayer の方の copyRect メソッドの引数が “...” になってないね。
messageLayercopyRect メソッドの引数で1つだけ変わってるのがあるでしょ。
あ、ホントだ。第3引数が src じゃなくて messageLayer になってるね。
履歴メッセージをスクロールする時に、第3引数(コピー元のレイヤ)を this にして copyRect メソッドを呼び出してたよね。
§10.11§10.12 参照。
うん。copyRect メソッドで履歴メッセージを元々表示されてた位置からスクロールした後の位置に移動するから、 コピー元とコピー先のレイヤがどっちもメッセージ履歴レイヤになるんだったよね。
そうそう。
で、messageLayer に履歴メッセージを表示する場合も、 copyRect メソッドを呼び出す時はコピー元レイヤを自分自身、つまり messageLayer にしなくちゃいけないわけ。
確かにそーなるね。
でも、ここsrc って messageLayer じゃなくてメッセージ履歴レイヤになってるわけでしょ。
え、そーなの?
だって、これExtendedHistoryLayer クラスの copyRect メソッドなんだから、第3引数(src)を this にしてこのメソッドを呼び出したら、src はメッセージ履歴レイヤってことになるでしょ?
あ、そっか。
だから、messageLayercopyRect メソッドを呼び出す時には、 第3引数を messageLayer にする必要があるの。
なるほどね。
それじゃ次はメッセージ履歴レイヤに表示されてる文字を消すのに使う clearBack メソッドを見てくね。
clearBack メソッドについては §10.6 参照。

ExtendedHistoryLayer クラスの clearBack メソッド>

function clearBack(n)
{
    // メッセージ履歴レイヤを塗りつぶす色を設定します
    var color = messageLayer !== void ? 0x00000000 : 0xc8000000;
    // レイヤの描画形式をアルファチャンネルつき画像用の形式に設定します
    face = dfAlpha;
    if(n === void)
    {
        // n が void の時はレイヤ全体をクリアします
        fillRect(0, 0, width, height, color);
    }
    else
    {
        // n が指定されている場合は...
        if(verticalView)
        {
            // 縦書きなら n 列目をクリアします
            fillRect(width - marginR - (n + 1) * lineHeight, controlHeight,
                lineHeight, height - controlHeight, color);
        }
        else
        {
            // 横書きなら n 行目をクリアします
            fillRect(0, n * lineHeight + controlHeight + marginT,
                width, lineHeight, color);
        }
    }
}

clearBack メソッドは今までの3つのメソッドとはやってることがちょっと違う感じだね。
まぁね。でも別にややこしい事はやってなくて、 元々の(HistoryLayer クラスの)clearBack メソッドと違ってるのは2か所だけだよ。
あ、そーなんだ。
まず1か所目は最初のとこだね。
最初のとこって…color って変数に何か値を代入してるとこのこと?
そう。どんな値を代入してるかわかる?
えっと…messageLayervoid じゃなかったら 0x00000000 って値を代入してて、 messageLayervoid だったら 0xc8000000 を代入してるから…
うん。
つまり、メッセージ履歴画面に背景画像を表示する場合は messageLayervoid じゃないから color0x00000000 になって、 背景画像を表示しない場合は 0xc8000000 になるんだね。
ん、そういうことだね。
ところでこの 0x00000000 とか 0xc8000000 ってどんな値なの?
この color っていう変数には色の値を AARRGGBB 形式で代入してるんだけど、色の値の指定の仕方は覚えてるかな?
ん〜…確か前に出てきてるよね。
AA が不透明度で、 RRGGBB がそれぞれ赤色・緑色・青色の強さ、だったかな?
§10.6 参照。
そうそう。
それじゃ 0x00000000 ってどんな色だった?
確か、AA00 だと透明色になるんじゃなかったっけ?
そうだね。
じゃ、0xc8000000 はどんな色だった?
AA だけが c8 で、 RRGGBB が全部 0 だから… 不透明度が c8 の黒色、かな。
c8 ってどんな値だった?
えっと、AARRGGBB 形式で色を指定する時って、普通の数字で指定するんじゃなかったと思うけど…
c8 っていくつになるんだったっけ?
AARRGGBB 形式で色を指定する時には16進数で値を表すことになってるから、 c8 ってのは普通の数字(10進数)だと 200 だよ。
じゃあ 0xc8000000 は不透明度が 200 の黒色になるんだね。
そ。で、もう1か所 HistoryLayer クラスの clearBack メソッドと違う所が、fillRect メソッドの最後の引数。
ちなみに3つある fillRect メソッド全部の最後の引数が変わってるよ。
fillRect メソッドの最後の引数っていうと…塗りつぶす色を指定する引数だよね。
あ、それがさっきの color っていう変数になってるんだね。
だから、メッセージ履歴画面に背景画像を表示するかしないかで、 履歴メッセージを消す時にレイヤを塗りつぶす色を変えてるわけね。
背景画像を表示する場合は透明色(0x00000000)で塗りつぶして、 表示しない場合は不透明度 200 の黒色(0xc8000000)で塗りつぶすってことだよね?
うん。なんでそうしてるかわかる?
う〜ん…背景画像を表示するかしないかで、塗りつぶすレイヤが違うからかな?
さっき fillRect メソッドをオーバーライドしてたから、 背景画像を表示する時は messageLayer を塗りつぶして、 表示しない時はメッセージ履歴レイヤを塗りつぶすわけでしょ?
そーだね。
でもなんで色を変える必要があるんだろ…?
普通の(カスタマイズしてない)メッセージ履歴画面って背景色が半透明の黒色になってるでしょ。
そっか。だから塗りつぶす色が 0xc8000000 になるんだ。
で、メッセージ履歴画面に背景を表示する場合は、 履歴メッセージ表示用のレイヤ(messageLayer)の奥に背景画像が表示されるから、 messageLayer を半透明の黒色で塗りつぶしたら、背景が暗くなっちゃうよね。
じゃあ背景がちゃんと表示されるように messageLayer を透明色で塗りつぶしてるってこと?
そういうこと。透明色で塗りつぶせば背景画像はそのまま表示されるからね。
なるほどね。
じゃ次のメソッドにいくね。
次にオーバーライドするのは dispUninit メソッドだよ。
※スクリプトファイル内では、clearBack メソッド中で使用している face プロパティも念のためにオーバーライドしていますが、face プロパティはオーバーライドしなくても正常に動作するため、説明は割愛させて頂きます。なお、face プロパティでは、背景画像を表示するかしないかでプロパティの取得/設定先を変えています。
dispUninit メソッドって?
dispUninit メソッドはメッセージ履歴画面を閉じる時に呼び出されるメソッドだよ。
じゃあ dispInit メソッドの逆みたいな感じ?
そーだね。
ただ、HistoryLayer クラスの dispUninit メソッドは dispInit メソッドほど色んなことはしてなくて、 メッセージ履歴レイヤの visiblefalse にしてるくらいだね。
※その他に removeMode メソッドを呼び出してレイヤのモーダル状態(メッセージ履歴レイヤとその子レイヤのみがフォーカスやマウスメッセージを受け取れる状態)を解除しています。
へぇ、そーなんだ。
で、その dispUninit メソッドをこんなふうにオーバーライドするんだ。

ExtendedHistoryLayer クラスの dispUninit メソッド>

function dispUninit()
{
    deleteMessageLayer(); // メッセージ履歴表示用レイヤを削除します
    super.dispUninit(); // スーパークラスの dispUninit メソッドを呼び出します
}

deleteMessageLayer っていうメソッドを呼び出してから、 スーパークラスの dispUninit メソッドを呼び出してるみたいだけど…
deleteMessageLayer メソッドって今回新しく作ったメソッド?
そだよ。
deleteMessageLayer メソッドは要らなくなった messageLayer を無効化するメソッドなんだ。
メッセージ履歴画面が閉じると messageLayer は必要なくなるから、 ここで deleteMessageLayer メソッドを呼び出してるの。
messageLayer ってメッセージ履歴画面を閉じたら無効化しちゃうんだ?
ん。メッセージ履歴画面を表示してない時は別に必要ないレイヤだから、 メッセージ履歴画面を表示した時(dispInit メソッドが呼び出された時)に作って、 メッセージ履歴画面を閉じた時(dispUninit メソッドが呼び出された時)に無効化するようにしてるんだ。
そっか。
じゃ deleteMessageLayer メソッドのスクリプトを見てくね。

deleteMessageLayer メソッド>

function deleteMessageLayer()
{
    if(messageLayer !== void)
    {
        invalidate messageLayer;
        messageLayer = void;
    }
}

このメソッドは見ての通り messageLayer を無効化してるだけだから、特に問題ないよね?
うん。
…あ、でも messageLayer を無効化した後に messageLayervoid を代入してるのがちょっと気になるかな。
最初の if の条件で messageLayervoid じゃないかどうかチェックしてるでしょ。
うん。void じゃなかったら無効化してるよね。
だから、messageLayer を無効化した後に messageLayervoid を代入することで、 messageLayer はもう存在しないよってことをはっきりさせてるわけ。
そうしないと、例えば messageLayer を無効化した後でまた deleteMessageLayer メソッドを呼び出したりした時に、 もう無効化されてる messageLayer をもう一回無効化しようとしてエラーになっちゃったりするからね。
そっか。messageLayer を無効化しても、 自動的に messageLayervoid になるわけじゃないんだよね。
ん、そこはちょっと注意する必要があるよね。
あとはいいかな?
うん。
じゃ最後は ExtendedHistoryLayer クラスのデストラクタを見てくね。

ExtendedHistoryLayer クラスのデストラクタ>

function finalize()
{
    deleteMessageLayer(); // メッセージ履歴表示用レイヤを削除(無効化)します
    invalidate scrollBar if scrollBar !== void// スクロールバーを無効化します
    super.finalize(); // スーパークラスのデストラクタを呼び出します(closeButton はここで無効化されます)
}

deleteMessageLayer メソッドを呼び出して、 それからスクロールバーオブジェクトを無効化して、 最後にスーパークラスのデストラクタを呼び出してるんだね。
履歴メッセージ表示用のレイヤ(messageLayer)とスクロールバーオブジェクト(scrollBar)は元々のメッセージ履歴レイヤ(HistoryLayer)クラスには無いものだから、 ここで無効化してるわけだね。
これも特に問題ないんじゃないかな?
うん、おっけー。
はい、じゃこれでメッセージ履歴画面に背景画像を表示するカスタマイズは完了だよ。
え、もうおしまい?
なんか基本編と比べるとかなり短い気がするんだけど。
背景画像を表示するだけなら、そんなにたくさんやることがあるわけじゃないからね。
それと基本編でやることが色々ありすぎたってのもあるしね…
確かに基本編は長過ぎたよねぇ…
まぁとにかくこれで背景画像は表示できるようになったから、 次回からはメッセージ履歴アクションを実行できるボタンを作っていくね。
りょ〜かい。
それじゃ、また次回ね!


前へ | TOP