10.5 メッセージ履歴のカスタマイズ 〜基本編〜(その2)

今回は実際のスクリプトを見ながら dispInit メソッドでやってることをチェックしてくね。
は〜い。
前回、元々の履歴レイヤ(HistoryLayer クラス)の dispInit メソッドと、 カスタマイズした履歴レイヤ(ExtendedHistoryLayer クラス)の dispInit メソッドの両方を使うって言ったよね。
元々の履歴レイヤとおんなじ処理をしてる部分は HistoryLayer クラスの dispInit メソッドを使って、 カスタマイズしてる部分は ExtendedHistoryLayer クラスの dispInit メソッドを使うんだったよね。
そうそう。
その辺は前回 dispInit メソッドのフローチャートで表したから、 今回はこのフローチャートの流れに沿ってスクリプトを見てくことにするね。
りょ〜かい。
じゃあまずは STEP 1 から見てくね。
STEP 1 はスクロールバーとか閉じるボタンを作るようにしてるから、 カスタマイズした履歴レイヤの方の STEP 1 を実行するんだよね?
ん、そう。
ってワケだから、まずは ExtendedHistoryLayer クラスの dispInit メソッドを見てみるね。

ExtendedHistoryLayer クラスの dispInit メソッド>

function dispInit()
{
    // スーパークラス(HistoryLayer クラス)の dispInit メソッドを呼び出します
    // (メッセージ履歴テキストの書き込みなどはここで実行されます)
    super.dispInit();

    // スクロールバーの設定をします
    if(canScroll)
    {
        // スクロールバーが必要な場合は canScroll が true になります
        scrollBar.maxVal = dispStart; // 最大値を設定します
        // スライダー(ドラッグして動かせる部分)の長さを設定します
        scrollBar.ratio = everypage ? (1 / dataPages) : (dispLines / dataLines);
        scrollBar.value = dispStart; // 現在値を設定します
    }
    // スクロールバーが必要(canScroll が true)なら表示状態
    // 不必要(canScroll が false)なら非表示状態にします
    scrollBar.visible = canScroll;
}

色々やってるわりには意外とシンプルそーだね…
ってゆーか、STEP 1 に書いてある“makeButtons メソッド”ってのを呼び出してる部分がないんだけど?
ん、ここでは呼び出してないからね。
え、どーいうコト?
ExtendedHistoryLayer クラスのスーパークラスってどのクラスだかわかる?
えっと、ExtendedHistoryLayer クラスは元々のメッセージ履歴レイヤのクラスを継承して作ってるんだから、 HistoryLayer クラスじゃないの?
そうだね。
じゃここで“super.dispInit();”を実行すると…?
スーパークラスの dispInit メソッドが呼び出されるから…
つまり HistoryLayer クラスの dispInit メソッドが呼び出されるってことだよね?
そういうこと。
それじゃ HistoryLayer クラスの方の dispInit メソッドのスクリプトを見てみるね。

HistoryLayer クラスの dispInit メソッド(HistoryLayer.tjs より抜粋)>

function dispInit()
{
    // 全部再描画と初期設定
    makeButtons(); // ボタンを作成

    // メッセージ履歴アクション関係の設定
    lastLine = currentLine;
    endAction();
    lastAction = currentAction;

    // antialiased…メッセージ履歴に表示する文字にアンチエイリアスをかけるかどうか
    // (基本的に Config.tjs の defaultAntialiased の設定に従います)
    antialiased = window.chDefaultAntialiased;

    // メッセージをすべて消去
    clearBack();

(以下略)
※コメントを追加しています。

あ、makeButtons メソッドが呼び出されてる。
ってワケだから、ExtendedHistoryLayer クラスの dispInit メソッドを呼び出すと、 最初に makeButtons メソッドが呼び出されるの。
そっか〜。
…あ、でもここで makeButtons メソッドを呼び出したら、 ExtendedHistoryLayer クラスじゃなくって HistoryLayer クラスの方の makeButtons メソッドが呼び出されちゃうんじゃないの?
確かにそんな気がしないでもないけどね。
でも大丈夫。ExtendedHistoryLayer クラスに makeButtons メソッドを作っとけば、 ちゃんとそっちの方が呼び出されるよ。
えっ、そーなの? なんで?
ん〜、そーだね…簡単に言うと、元々呼び出されてるのが ExtendedHistoryLayer クラスの方の dispInit メソッドだったから、だね。
つまり、まず最初に ExtendedHistoryLayer クラスの dispInit メソッドが呼び出されてて、 でその中のこの部分でスーパークラス、つまり HistoryLayer クラスの dispInit メソッドが呼び出されて、 さらにその中のこの部分makeButtons メソッドが呼び出されてる、って流れになってるでしょ。
うん、そーだね。
だから、一番最初に呼び出されてるのは ExtendedHistoryLayer クラスの dispInit メソッドってことだよね。
うん。
こーいう時は、たとえ HistoryLayer クラスのメソッドの中で makeButtons メソッドが呼び出されてても、 HistoryLayer クラスじゃなくって ExtendedHistoryLayer クラスの方の makeButtons メソッドが呼び出されるってことになってるんだ。

<メソッド実行の流れ>

へぇ、そーなんだ。なんかムズカシイね…
まぁこの辺はクラスの継承の考え方に慣れないとちょっとわかりにくいかもね。
とりあえず ExtendedHistoryLayer クラスの makeButtons メソッドが呼び出されるってことはわかってもらえたと思うから、 次は STEP 1 の中身、ExtendedHistoryLayer クラスの makeButtons メソッドのスクリプトを見ていくね。

ExtendedHistoryLayer クラスの makeButtons メソッド>

function makeButtons()
{
    if(scrollBar !== void)
        return// すでにスクロールバーが作成されている場合は何もしません

    // verticalView は HistoryLayer クラス(スーパークラス)のメンバ変数で
    // Config.tjs の HistoryLayer_config メソッド内で設定できます
    if(verticalView)
    {
        // 縦書き(verticalView が true)なら水平スクロールバーを作ります
        scrollBar = new HorizontalScrollBar(window, this, onValueChanged);
    }
    else
    {
        // 横書き(verticalView が false)なら垂直スクロールバーを作ります
        scrollBar = new VerticalScrollBar(window, this, onValueChanged);
    }
    scrollBar.setSize(scrollBarWidth, scrollBarHeight);
    scrollBar.setPos(scrollBarLeft, scrollBarTop);
    scrollBar.absolute = 2000;
    scrollBar.baseColor = scrollBarBaseColor;
    scrollBar.buttonColor = scrollBarButtonColor;
    scrollBar.buttonCaptionColor = scrollBarButtonCaptionColor;
    scrollBar.sliderColor = scrollBarSliderColor;
    scrollBar.minVal = 0; // スクロールバーの値の下限を 0 に設定します(下限は常に 0 です)

    // 閉じるボタンを作成します
    closeButton = new HistoryButtonLayer(window, this);
    if(closeButtonStorage != "")
    {
        // 閉じるボタン用の画像が指定されていれば読み込みます
        closeButton.loadImages(closeButtonStorage);
    }
    else
    {
        // 画像が指定されていなければ caption, color, captionColor, width, height プロパティを設定します
        closeButton.caption = closeButtonCaption;
        closeButton.color = closeButtonColor;
        closeButton.captionColor = closeButtonCaptionColor;
        closeButton.setSize(closeButtonWidth, closeButtonHeight);
    }
    closeButton.setPos(closeButtonLeft, closeButtonTop);
    closeButton.absolute = 3000;
    closeButton.hint = closeButtonHint;
    closeButton.visible = true;
}

結構長いね…
ほとんど設定関係のスクリプトだけだから、特に難しくはないと思うよ。
ふぅん、そーなんだ。
じゃまず最初はこの if のとこからね。
これって scrollBarvoid じゃなかったら、何もせずに return するってことだよね。
前回、 普通のメッセージ履歴画面は最初に表示する時だけ「前ページ」とかのボタンを作るって言ったでしょ。
うん、そーだったね。
カスタマイズしたメッセージ履歴画面でも、 スクロールバーとか閉じるボタンは最初に表示する時だけ作るようにしてるの。
じゃあもしかして、 最初にメッセージ履歴画面を表示する時はまだスクロールバーが作られてないから scrollBarvoid だけど、2回目以降に表示する時はスクロールバーが作られてて scrollBarvoid じゃなくなってるから、 何もせずに return してるってこと?
ん、そのとーり。
scrollBarExtendedHistoryLayer クラスのメンバ変数で、(カスタマイズした)メッセージ履歴画面を表示する前は void になってて、 一度メッセージ履歴画面を表示してスクロールバーを作ったら、 その後はスクロールバーオブジェクト(の参照)になって void じゃなくなるからね。
うんうん。
あ、でもチェックするのって scrollBar だけでいいの?
閉じるボタンも最初に表示した時に作るんでしょ?
閉じるボタンのオブジェクトも makeButtons メソッドの中で作るから、scrollBarvoid だったら閉じるボタンも作られてないってことだし、 scrollBarvoid じゃなかったら閉じるボタンも作られてるってことになるの。
つまり、scrollBar だけチェックすれば OK ってことだね。
あ、そっか。なるほど。
じゃ次いくね。
次はスクロールバーオブジェクトを作ってるとこなんだけど、 スクロールバーには2種類あるから、ここの if の条件でどっちを作るかを判断してるんだ。
スクロールバーって2種類あるの?
履歴メッセージが横書きか縦書きかでメッセージがスクロールする方向が違うから、 別々のスクロールバーを使うんだ。
そっか。横書きだと上下にスクロールするけど、 縦書きだと左右にスクロールするもんね。
だから、履歴メッセージを横書きで表示する場合は垂直スクロールバーを使って、 縦書きで表示する場合は水平スクロールバーを使うの。
if のとこで verticalView をチェックしてるってことは、これが横書きか縦書きかを表してる変数ってこと?
そ。verticalView は縦書き表示にしてる時に true になって、横書き表示にしてる時は false になる変数だよ。
ちなみにこの値は Config.tjs で設定できるようになってるよ。

verticalView の設定(Config.tjs より抜粋)>

//---------------------------------------------- メッセージ履歴の設定 -----

function HistoryLayer_config()
{
// メッセージ履歴の設定です

(中略)

// ◆ 縦書きの場合は true
;verticalView = false;

(以下略)

で、ここverticalView の値をチェックして、 true になってたら水平スクロールバーを作って、 false になってたら垂直スクロールバーを作ってるの。
えっと、それじゃあ HorizontalScrollBar が水平スクロールバー用のクラスで、 VerticalScrollBar が垂直スクロールバー用のクラスってことかな?
ん、そうだよ。
スクロールバーのクラスの説明は省略させてもらうけど、一応コンストラクタの引数だけは確認しとくね。
まず第1引数の window と第2引数の thisLayer クラスのコンストラクタの第1・第2引数と同じだから問題ないよね。
Layer クラスのコンストラクタについては §3.2 参照。
確か第1引数が所属するウィンドウで、第2引数が親レイヤだったよね?
そう。ちなみにスクロールバーが所属するウィンドウ(window)は kag オブジェクトで、親レイヤ(this)はメッセージ履歴レイヤ(kag.historyLayer)になるよ。
第3引数の“onValueChanged”ってゆーのは?
第3引数にはスクロールバーが操作されてスライダーの位置が変わった時に呼び出されるメソッドを指定するんだ。
スクロールバーの“▲”ボタンや“▼”ボタンをクリックしたり、スライダーをドラッグしたりすると、 メッセージがスクロールするでしょ。
そーだね。
履歴メッセージをスクロールする処理は手動でやらなくちゃいけないから、 スクロールバーのボタンをクリックしたりスライダーをドラッグしたりすると、 コンストラクタの第3引数に指定したメソッド(onValueChanged メソッド)が呼び出されるようにしてるんだ。
じゃあ onValueChanged メソッドで履歴メッセージをスクロールする処理をするってこと?
そういうこと。
onValueChanged メソッドはまた今度見てくつもりだけど、 とりあえず履歴メッセージをスクロールするためのメソッドって思っといて。
わかった。
じゃ次ね。
スクロールバーのオブジェクト(scrollBar)を作ったら、 この辺でスクロールバーの設定をやってるんだ。
なんか色々設定してるみたいだね。
スクロールバー関係の設定を Override.tjs に書いたのは覚えてる?
確かメッセージ履歴レイヤをカスタマイズするための設定を Override.tjs の中に Config.tjs みたいな感じで書き込んでて、 その中にスクロールバーの設定項目もあったよね。
§10.2 参照。
そうそう。その設定項目を実際にスクロールバーオブジェクトに設定してるのがこの辺のスクリプトなの。
そー言われれば、scrollBarWidth とか scrollBarHeight って設定項目の中にあったよね。
設定項目は結構たくさんあるから、表にまとめてみるね。

<スクロールバーの設定項目>

scrollBar のプロパティOverride.tjs での設定項目設定項目の意味
widthscrollBarWidth
heightscrollBarHeight高さ
leftscrollBarLeft左端位置
topscrollBarTop上端位置
absoluteなし※1重ね合わせ順序
baseColorscrollBarBaseColor地の色※2
buttonColorscrollBarButtonColorボタンの色※2
buttonCaptionColorscrollBarButtonCaptionColorボタンの文字の色※2
sliderColorscrollBarSliderColorスライダーの色※2
※1:重ね合わせ順序はあまり重要ではないので適当に設定しています。
※2:これらの色についてはこちらの図を参照してください。

基本的に Override.tjs で設定してる値をスクロールバーオブジェクトのプロパティにセットしてるだけだし、 setSize メソッドとか setPos メソッドは Layer クラスの setSize メソッドや setPos メソッドと同じ意味だから、 特にわかりにくいとこはないんじゃないかな。
Layer クラスの setSize, setPos メソッドについては §3.2 参照。
ん〜、そーだね…大体わかるかな。
あ、最後の scrollBar.minVal ってプロパティはこの表に書いてないみたいだけど?
minVal プロパティは後で詳しく説明しようと思ってたから表に入れなかったんだけど、 一応簡単に説明しといた方がいいかな?
そーだね。ちょっと気になるし。
minVal プロパティは、 垂直スクロールバーのスライダーが一番上にある時(水平スクロールバーのスライダーが一番左にある時)に、 履歴メッセージの何行目からが表示されるようにするかを設定するプロパティだよ。
んー、ちょっとよくわかんないかな?
例えば、エディタとかで(垂直)スクロールバーのスライダーが一番上にある時って、 テキストの最初の部分が表示されてるでしょ?
そだね。
minVal プロパティを 0 に設定すると、 垂直スクロールバーのスライダーが一番上にある時(水平スクロールバーのスライダーが一番左にある時)に、 履歴メッセージの0行目、つまり一番最初の行から表示されるようになるの。
え? 0行目? 1行目じゃなくて?
履歴メッセージデータは配列に記録されてるから、一番最初の行は0行目なんだ。
配列の最初の要素は0番目だからね。
そーなんだ。
じゃ次いってもいいかな?
あ、あとスクロールバーのスライダーが一番下にある時の設定ってやらなくていいの?
垂直スクロールバーのスライダーが一番下にある時(水平スクロールバーのスライダーが一番右にある時)は、 履歴メッセージの最後の部分が表示されるわけだけど、 履歴メッセージの最後の行が何行目になるかは履歴メッセージの長さによって変わるし、 この時点では何行あるか判らないから、もうちょっと後でやるの。
だから詳しくはまた後で見てくことにするね。
そっか。わかった。
それじゃ次は閉じる(×)ボタンを作るスクリプトを見てくね。
closeButton = new HistoryButtonLayer(window, this);”のとこで閉じるボタンを作ってるんだよね?
ん、そうだよ。
HistoryButtonLayer クラスって今までに見たことないクラスだと思うんだけど?
HistoryButtonLayer クラスは、閉じるボタン用に今回新しく作ったクラスだよ。
わざわざ新しく作ったってことは、何か特別な機能とかがあるってこと?
ん〜、特別ってほどの機能はないけど、基本的なボタンのクラス(ButtonLayer クラス)には無い機能をちょっと使いたかったから作ったんだ。
ButtonLayer クラスについては §5.3 参照。
それってどんな機能なの?
ボタンをクリックした時に親レイヤ(メッセージ履歴レイヤのことね)のメソッドを呼び出す機能だよ。
この機能があるとわりと便利だからね。
ふぅん、そーなんだ。
じゃ簡単に HistoryButtonLayer クラスのスクリプトも確認しとくね。

HistoryButtonLayer クラス>

class HistoryButtonLayer extends ScrollBarButtonBaseLayer
{
    // コンストラクタ
    function HistoryButtonLayer(window, parent)
    {
        // スーパークラスのコンストラクタを呼び出します
        super.ScrollBarButtonBaseLayer(window, parent);
    }

    // デストラクタ
    function finalize()
    {
        // スーパークラスのデストラクタを呼び出します
        super.finalize(...);
    }

    // マウスのボタンが離された時に呼び出されるメソッド(オーバーライド)
    function onMouseUp(x, y, button, shift)
    {
        if(enabled && button == mbLeft)
            parent.onButtonClick(this); // 親レイヤ(=履歴レイヤ)の onButtonClick メソッドを呼び出します
        super.onMouseUp(...);
    }
}

見ての通りシンプルなクラスだから、特に難しくはないと思うよ。
追加した機能は、クリックされたら親レイヤ(parent)の onButtonClick っていうメソッドを呼び出すってのだけだよ。
onMouseUp メソッドがボタンが押された時に呼び出されるメソッドなんだよね?
そうだよ。ま、正確にはレイヤ(ボタン)の上でマウスのボタンが離された時に呼び出されるメソッドだけどね。
あと if の条件でチェックしてることはわかる?
enabledtruebuttonmbLeft の時に、 親レイヤの onButtonClick メソッドが呼び出されるんだよね。
button に代入される値(mbLeft など)については §3.7 参照。
そ。
つまり、ボタンが使用可能な状態になってて、あと押されたボタンがマウスの左ボタンだったら、 親レイヤの onButtonClick メソッドが呼び出されるってことかな?
ん、そういうこと。
HistoryButtonLayer クラスは特に問題ないでしょ?
ん〜…HistoryButtonLayer クラスのスーパークラスになってる ScrollBarButtonBaseLayer ってクラスが気になるんだけど、 これって名前からするとスクロールバー用のボタンのクラスなんじゃない?
あっ、そうそう。
HistoryButtonLayer クラスはちょっとワケあってスクロールバー用のボタンのクラスを継承して作ってるんだ。
どんなワケがあるの?
閉じるボタンに画像を表示しない時に、スクロールバー用のボタンと閉じるボタンの見た目を似たような感じにするためだよ。その方がデザイン的に統一された感じになっていいかなって思ったから。
そーなんだ。
じゃあスクロールバー用のボタンにも何か特別な機能とかがあるの?
んーん、スクロールバーのボタンっぽく見えるように、 普通のボタンとちょっとだけ見た目を変えてるだけだよ。
じゃあ普通のボタンと同じように使えるってこと?
うん、機能的には普通のボタン(ButtonLayer クラス)と全く同じだよ。
ってワケで、ScrollBarButtonBaseLayer クラスは ButtonLayer クラスと同じように使えるから、 ScrollBarButtonBaseLayer クラスの説明は省略させてもらうね。
りょーかい。
んじゃ閉じるボタンを作るとこに戻って…
まずこの if のとこからね。
closeButtonStorage って?
閉じるボタンに表示する画像ファイルのことだよ。
メッセージ履歴の設定ファイルで設定できるようにしてたでしょ。
§10.3 参照。
あ、Override.tjs に書いてたののことだね。
そ。閉じるボタンに画像を表示するかしないかで設定が変わるから、 ここの if のとこで画像を表示するかどうかをチェックしてるの。
えっと、条件が closeButtonStorage != "" になってるから、closeButtonStorage が空文字列じゃなかったら if ブロックが実行されるってことだよね。
これってつまり、閉じるボタンに画像を表示する場合は if ブロックの方が実行されるってこと?
そう。で、その場合は loadImages メソッドで閉じるボタン用の画像を読み込むわけだね。
※(ButtonLayer クラスの)loadImages メソッドについては §5.3 参照。
じゃあ閉じるボタンに画像を表示しない場合は else ブロックの中身が実行されるってことだね。
else ブロックの中身で設定してるのも、 Override.tjs に書き込んだ設定項目なんだよね?
ん。ちなみに閉じるボタンに画像を表示しない場合は、 閉じるボタンに表示する文字列(closeButtonCaption)と、 閉じるボタンの色(closeButtonColor)と、 表示する文字列の色(closeButtonCaptionColor)と、 あとボタンの縦横のサイズ(closeButtonWidth, closeButtonHeight)の5つの要素を設定するよ。
画像を表示しないと色々設定する項目があるんだね。
まぁね。で、あとこの辺で画像を表示してもしなくても設定する必要があるプロパティを設定してるんだ。
setPos メソッドで表示位置を設定してて、 absolute プロパティが重ね合わせ順序で、 hint プロパティがボタンの上にマウスカーソルを重ねると表示されるメッセージで、 visible プロパティが表示状態かどうか、だよね?
うん。まとめるとこんな感じだね。

<閉じるボタンの設定項目>

closeButton のプロパティOverride.tjs での設定項目設定項目の意味
closeButtonStorage表示する画像ファイル名
captioncloseButtonCaption表示するテキスト※1
colorcloseButtonColorボタンの色※1
captionColorcloseButtonCaptionColor表示するテキストの色※1
widthcloseButtonWidth※1
heightcloseButtonHeight高さ※1
leftcloseButtonLeft左端位置
topcloseButtonTop上端位置
absoluteなし※2重ね合わせ順序
visibleなし(常に true可視状態か
※1:これらの項目はボタンに画像を表示しない場合のみ有効です。
※2:重ね合わせ順序はあまり重要ではないので適当に設定しています。

さて、じゃ makeButtons メソッドは一通りチェックできたから、 これで STEP 1 は OK だね。
やっと STEP 1 が終わりかぁ…まだ先は長そーだね。
まーメッセージ履歴レイヤ関係は結構複雑だからね。
それじゃ今回はこの辺にして、STEP 2 からは次回見てこっか。
うん、そーだね。
それじゃ、また次回ね!


前へ | TOP | 次へ