Section 3.15 時計の実装(その1)

今回から、§3.10で作ったスクリプトをベースにして、色々機能を追加していくね。
うん!
最初は何からやるの?
まずはアラーム関係からね。
§2.4で作った Clock クラスを使って、 アラームを鳴らす時刻を設定したり、あとアラーム用のファイルを設定したり、タイマーイベントで時刻をチェックして、設定された時刻になってたらアラームを鳴らしたりするよ。
うん、りょーかい!
じゃあ、まずはコンストラクタから作っていくね。
はーい!
§3.10で作ったコンストラクタにオブジェクトを追加してみて。
追加するオブジェクトはこれね。

<コンストラクタに追加するオブジェクト>

  1. Clock クラスのオブジェクト
    • メンバ変数名は clock にすること。

  2. WaveSoundBuffer クラスのオブジェクト
    • メンバ変数名は buffer にすること。
    • ループ再生すること。

  3. 「終了」メニュー
    • メンバ変数名は menuQuit にすること。
    • ルートメニューの子メニューにすること。
    • Alt + Q で選択できるようにすること。

  4. 「アラーム」メニュー
    • メンバ変数名は menuAlarm にすること。
    • ルートメニューの子メニューにすること。
    • Alt + A で選択できるようにすること。

  5. 「アラームファイルを設定」メニュー
    • メンバ変数名は menuFile にすること。
    • 「アラーム」メニューの子メニューにすること。
    • Alt + F で選択できるようにすること。

  6. 「アラームをセット」メニュー
    • メンバ変数名は menuSet にすること。
    • 「アラーム」メニューの子メニューにすること。
    • Alt + S で選択できるようにすること。

  7. 「アラームを解除」メニュー
    • メンバ変数名は menuCancel にすること。
    • 「アラーム」メニューの子メニューにすること。
    • Alt + C で選択できるようにすること。

  8. FileSelector クラスのオブジェクト
    • メンバ変数名は selector にすること。

結構いっぱいあるねぇ。
まぁね。でも今までに出てきたオブジェクトばっかりだから、問題なく作れるでしょ?
そだね。じゃあ作ってみるね。

<オブジェクトを追加したコンストラクタ>

function ClockWindow()
{
    super.Window();  // スーパークラスのコンストラクタを呼び出します

    add(new Layer(thisnull));  // プライマリレイヤを作ります

    // プライマリレイヤに画像を読み込みます
    with(primaryLayer)
    {
        .loadImages("frame.png");   // プライマリレイヤに frame.png を読み込みます
        .setSizeToImageSize();      // プライマリレイヤのサイズを画像サイズに合わせます

        // ウィンドウのクライアント領域のサイズをプライマリレイヤのサイズに合わせます
        setInnerSize(.width, .height);
    }

    // 日時を書くためのレイヤを作ります
    messageLayer = new Layer(this, primaryLayer);
    add(messageLayer);
    with(messageLayer)
    {
        .setPos(22, 22, 114, 68);        // サイズを 114×68、位置を (22, 22) にします
        .font.face = "MS Pゴシック";  // フォントを「MS Pゴシック」にします
        .font.height = 24;               // フォントの高さを 24 ピクセルに設定します
        .visible = true;
    }

    // 1. Clock クラスのオブジェクトを作ります
    clock = new Clock();
    add(clock);

    // 2. WaveSoundBuffer クラスのオブジェクトを作ります
    buffer = new WaveSoundBuffer(this);
    add(buffer);
    buffer.looping = true;

    // 3.「終了」メニューを作ります
    menuQuit = new MenuItem(this"終了(&Q)");
    menu.add(menuQuit);

    // 4.「アラーム」メニューを作ります
    menuAlarm = new MenuItem(this"アラーム(&A)");
    menu.add(menuAlarm);

    // 5.「アラームファイルを設定」メニューを作ります
    menuFile = new MenuItem(this"アラームファイルを設定(&F)");
    menuAlarm.add(menuFile);

    // 6.「アラームをセット」メニューを作ります
    menuSet = new MenuItem(this"アラームをセット(&S)");
    menuAlarm.add(menuSet);

    // 7.「アラームを解除」メニューを作ります
    menuCancel = new MenuItem(this"アラームを解除(&C)");
    menuAlarm.add(menuCancel);

    // 8. FileSelector クラスのオブジェクトを作ります
    selector = new FileSelector();
    add(selector);

    // タイマーオブジェクトを作ります
    timer = new Timer(this);
    add(timer);
    timer.interval = 1000;
    timer.enabled = true;

    drawTime();  // 日時を表示するメソッドを呼び出します

    visible = true;
}

ん〜、こんな感じでいいかな?
ん、オブジェクトの追加はこれで OK だね。
あと、他にもちょっと変更したり追加したりすることがあるから、説明していくね。
うん、わかった。
まず、このスクリプトをコンストラクタに追加するよ。

<コンストラクタに追加するスクリプト1(ウィンドウスタイルの設定)>

borderStyle = bsSingle;  // ウィンドウのサイズを変更不可にします

これってどういう意味なの?
borderStyleWindow クラスのプロパティで、ウィンドウのタイプや外見を設定できるんだ。
で、bsSingle っていうのは、サイズ変更ができないウィンドウを表す値。
つまり、ウィンドウのサイズを変更できなくしてるってこと。
なんでウィンドウのサイズを変更できなくするの?
ウィンドウのサイズが変えられると、時計の枠の画像サイズとウィンドウサイズが合わなくなって、見た目がヘンになっちゃうから。
KAG のウィンドウも、背景のサイズとウィンドウサイズが合わなくならないように、サイズが変更できなくなってるでしょ。
なるほど、確かにそうだね。
次は、このスクリプトを追加するね。

<コンストラクタに追加するスクリプト2(アラーム設定表示の初期化)>

System.title = caption = "Alarm OFF";  // アラーム設定の表示を初期化します

caption はウィンドウのタイトルバーに表示する文字列を設定できる Window クラスのプロパティで、 System.title は、えっと…タスクバーに表示する文字列を設定できるプロパティだったかな?
ん、そだよ。
起動した直後はアラームがセットされてないから、 このスクリプトでタスクバーとタイトルバーに「Alarm OFF」って表示してるんだ。
このスクリプトって1つの式の中に = が2つあるけど、これでいいの?
= 演算子は1つの式の中に複数書けるんだ。
え、そうなの?
うん。例えば…

a = b = c = 0;  // c, b, a の順に 0 が代入されます

って書くと、最初に c0 が代入されて、 次に b0 が代入されて、 最後に a0 が代入されるんだ。
つまり、こうすると…

c = 0;
b = 0;
a = 0;

っていうスクリプトを1行で書けるってワケ。
へぇ、そんな書き方ができるんだ。
複数の変数やプロパティに一度に同じ値を代入するときには便利かな。
だね。
あと、§3.10で作ったコンストラクタは、 プライマリレイヤを作ったすぐ後に setInnerSize メソッドを呼び出してたけど、 今回はメニューを作った後に呼び出すんだ。
え、なんで?
メニューバーを作ったからだよ。
? それってどういうこと?
ウィンドウのクライアントサイズを設定した後にメニューを作っても、 クライアントサイズは変わらないから、メニューバーの分だけクライアント領域が狭くなっちゃうんだ。
こんなふうに。

<クライアントサイズを設定した後にメニューを作った場合>

クライアントサイズを設定した後にメニューを作った場合のウィンドウ

なんかスクロールバーが表示されてるね…
プライマリレイヤがウィンドウのクライアント領域に収まらなくなっちゃったから、スクロールバーが表示されてるんだ。
あ、そうなんだ。
で、そうならないようにするために、メニューを作った後にクライアントサイズを設定するんだ。
なるほどね〜。
ってワケで、今回のコンストラクタはこんな感じ。

<コンストラクタ(完全版)>

function ClockWindow()
{
    super.Window();  // スーパークラスのコンストラクタを呼び出します

    add(new Layer(thisnull));  // プライマリレイヤを作ります

    // プライマリレイヤに画像を読み込みます
    with(primaryLayer)
    {
        .loadImages("frame.png");   // プライマリレイヤに frame.png を読み込みます
        .setSizeToImageSize();      // プライマリレイヤのサイズを画像サイズに合わせます
    }

    // 日時を書くためのレイヤを作ります
    messageLayer = new Layer(this, primaryLayer);
    add(messageLayer);
    with(messageLayer)
    {
        .setPos(22, 22, 114, 68);        // サイズを 114×68、位置を (22, 22) にします
        .font.face = "MS Pゴシック";  // フォントを「MS Pゴシック」にします
        .font.height = 24;               // フォントの高さを 24 ピクセルに設定します
        .visible = true;
    }

    // 1. Clock クラスのオブジェクトを作ります
    clock = new Clock();
    add(clock);

    // 2. WaveSoundBuffer クラスのオブジェクトを作ります
    buffer = new WaveSoundBuffer(this);
    add(buffer);
    buffer.looping = true;

    // 3.「終了」メニューを作ります
    menuQuit = new MenuItem(this"終了(&Q)");
    menu.add(menuQuit);

    // 4.「アラーム」メニューを作ります
    menuAlarm = new MenuItem(this"アラーム(&A)");
    menu.add(menuAlarm);

    // 5.「アラームファイルを設定」メニューを作ります
    menuFile = new MenuItem(this"アラームファイルを設定(&F)");
    menuAlarm.add(menuFile);

    // 6.「アラームをセット」メニューを作ります
    menuSet = new MenuItem(this"アラームをセット(&S)");
    menuAlarm.add(menuSet);

    // 7.「アラームを解除」メニューを作ります
    menuCancel = new MenuItem(this"アラームを解除(&C)");
    menuAlarm.add(menuCancel);

    // 8. FileSelector クラスのオブジェクトを作ります
    selector = new FileSelector();
    add(selector);

    // サイズ変更不可のウィンドウにします
    borderStyle = bsSingle;

    // ウィンドウのクライアント領域のサイズをプライマリレイヤのサイズに合わせます
    setInnerSize(primaryLayer.width, primaryLayer.height);

    // アラーム設定の表示を初期化します
    System.title = caption = "Alarm OFF";

    // タイマーオブジェクトを作ります
    timer = new Timer(this);
    add(timer);
    timer.interval = 1000;
    timer.enabled = true;

    drawTime();  // 日時を表示するメソッドを呼び出します

    visible = true;
}

それじゃ、コンストラクタはこれで OK ってことで、次はメソッドを追加していくね。
どんなメソッドを追加するの?
これが追加するメソッドと、あと変更するメソッドだよ。

<追加・変更するメソッド>

  1. [追加] setAlarmFile メソッド
    • 動作……アラーム用のファイルを設定します。
    • 引数……なし
    • 戻り値…なし
    • 備考……「アラームファイルを設定」メニューを選択したときに呼び出されます。

  2. [追加] setAlarm メソッド
    • 動作……アラームを鳴らす時刻を設定します。
    • 引数……なし
    • 戻り値…なし
    • 備考……「アラームをセット」メニューを選択したときに呼び出されます。
          アラームがセットされたら、タイトルバーとタスクバーに設定時刻を表示します。

  3. [追加] cancelAlarm メソッド

  4. [追加] checkAlarm メソッド
    • 動作……アラームを鳴らす時刻になったかどうかをチェックします。
    • 引数……なし
    • 戻り値…アラームがセットされていて、かつアラームを鳴らす時刻になっていれば true、そうでなければ false
    • 備考……タイマーイベントが起こるたびに呼び出されます。

  5. [追加] playAlarm メソッド
    • 動作……アラームを鳴らします。
    • 引数……なし
    • 戻り値…なし

  6. [追加] stopAlarm メソッド
    • 動作……アラームを止めます。
    • 引数……なし
    • 戻り値…なし
    • 備考……プライマリレイヤがクリックされるか、任意のキーが押されると呼び出されます。

  7. [変更] action メソッド
    • タイマーイベントの処理を追加します。
    • 各メニュー項目が選択された時の処理を追加します
    • アラームを止めるための処理を追加します

うわ、いっぱいあるねぇ…
確かに数は多いけど、作るのはそんなに難しくないから。
1つずつ順番に作っていけば、ちゃんとできるよ。
そうなの?
うん。
それじゃ、今回はとりあえずここまでにして、次回からメソッドを作っていくね。
うん、わかった。
じゃ、また次回ね!


前へ | TOP | 次へ