窓の工作室 〜 Windows アプリを作ろう!〜

〜 第4回 ボタンをつけてみる 〜

イベントドリブン型のプログラムを知る

え〜っと、2ヶ月ぶりの「窓の工作室」更新です(遅くなってすみませ〜ん)。

今回は前回からの続きですが、実際にプログラムの修正を行なうことによってウインドウにボタンをつける方法を考えてみようと思います。
と言うことで、前回使用した test プロジェクトを引き続いて使用します。前回ソースコードが書かれているファイルの名前を書いていませんでしたね。私はとりあえず main.c ということにしておきます(本当は test.c にしたかったんだけど、プロジェクト名と同じ名前では駄目みたいでした…)。

で、ここからは Windows プログラミングでは避けて通れない「イベントドリブン型のプログラム」というものを知る必要があります。
名前はものすごく難しそうですが、中身は大したことないです。以下でそれについて説明して、最後にボタンを表示する方法を書いてみます。

イベントとは?

Windows のプログラムをしようとするとたびたびイベントという単語が登場します。さて、このイベントとは何なのでしょうか。
簡単に言ってしまえば、「動作しているプログラムに対して外部から何かをした時に発生する命令みたいなもの」と言えばいいでしょうか。

例えば、ウインドウについているボタンを押した時とか、ウインドウのサイズを変更した時、さらには最初にウインドウが作成された時などにも発生しています。これは自動的に発生するようになっていて、これを使うかどうかはそのウインドウをプログラムした人が自由に決めることができます。

ですので、プログラムを作る人は「あるイベントが発生した時にどのような動作をするのか」ということをプログラムに記述していくことになります。
これを「イベントドリブン(イベント駆動)型のプログラム」と呼びます。
まったく新しい名前ではありますが、やっていることは前回説明した3つの指示(順次実行条件判定繰り返し実行)の単なる集合体です。
イベントが発生するまでは何もせず単にイベント待ちの状態を繰り返し(繰り返し実行)て、イベントが発生したらイベントの種類に従って(条件判定)対応する処理を実行(順次実行)するだけのことです。

実は前回の作業で作られたソースコードにもすでにこの処理が含まれていまして、一番最後の部分に書かれている WindowProcedure() という関数がそれに該当します。

LRESULT CALLBACK WindowProcedure(...)
{
    switch (message)
    {
           case WM_DESTROY:
           PostQuitMessage(0);
           break;
           default:
           return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

これは何をやっているのかと言うと、このプログラムを実行させると何もないウインドウが表示されたと思いますが、このプログラムを終了には現状ではタイトルバーの右端についている「X」ボタンを押すしかありません。
この「X」ボタンが押された時に実行される処理がここに書かれているのです。

ウインドウ上で発生したイベントはメッセージという形でプログラムに通知されます。プログラムの終了メッセージは WM_DESTROY という名前であらかじめ定義されていますので、この部分( case WM_DESTORY 〜 break; まで)の処理が実行されます。

それ以外のイベントによるメッセージは、その次にある default の部分で処理されますが、今回のプログラムでは特別なことは何もしません。

ここで使われている switch() 〜 case という構文はイベントドリブン型では非常によく使われるものです。switch 文の () の中が case で書かれている条件と一致したら、その case に書かれている部分を実行するというものです。
前回の条件判定で例に出した if() 文とはまた少し違う条件判定文ですね。

ボタンをくっつけてみる

それでは今回はこれまでの何もないウインドウにボタンを追加する方法を考えてみます。

さて、このボタンは一体いつ作成されるのがいいのでしょうか?ウインドウにマウスカーソルが入った時ですか?そうではありませんよね、もちろんウインドウが作成された時に一緒に作って欲しいですよね。
画面にウインドウが表示された時にはボタンもすでについていて欲しいですから。

と言うことで、どのようにすればいいのかが見えてきました。ウインドウが作られたというイベントが発生した時にボタンを作るような処理を書けばいいわけです。
ですので、処理を追加する場所は上で説明したところになりますね。

ウインドウが作られた時に発生するイベントは WM_CREATE というメッセージでプログラムに渡されます。
ちなみに WM とは Window Manager のことで、すべてのプログラムに共通な「ウインドウの枠(「X」ボタンがついているような部分)」を管理しているプログラムです、これがそのウインドウ内で発生したイベントをそれぞれのプログラムに通知してくれているのです。
最初に「イベントが自動的に発生」と書いたのは、この Window Manager がイベントチェックという面倒な処理を引き受けてくれているためです。これを自力で書こうとすると死にそうになりますよ(笑)。

では、とりあえず case WM_DESTROY: の上に次の処理を追加してください( static で始まる1行と case WM_CREATE から break; までの青色の部分です)。
hwndButton = から始まる行は複数行に分かれていますが、1行で書いてもらっても問題ありません。

LRESULT CALLBACK WindowProcedure(...)
{
    static HWND hwndButton = 0;

    switch (message)
    {
           case WM_CREATE:
           hwndButton = CreateWindow("button", "Click Here", 
                        WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                        0, 0, 200, 50, hwnd, (HMENU)1,
                        ((LPCREATESTRUCT)lParam)->hInstance, NULL);
           return 0;
           break;

           case WM_DESTROY:
           PostQuitMessage(0);
           :
    }
    return 0;
}

追加できたらコンパイル( Execute -> Compile )をして、タイプミスなどによるエラーがなければ実行( >> Execute << ボタンをクリック)してみてください。
今まで何もなかったウインドウの上に「Click Here」と書かれたボタンが置かれていると思います。

Button on Window

もちろんボタンを押されたイベントが発生した場合の処理を書いていませんので、ボタンを押しても何も起きませんが、とりあえずボタンをくっつけることができました。

プログラムを見ていただければ分かると思いますが、実際にボタンを作成する処理はたったの1行です。
ウインドウの上にボタンを作成するには CreateWindow() という関数を使用します(この関数はあらかじめ Dev-C++ で提供されていますので、我々が処理を作る必要はありません)。
「ボタンなのにウインドウ?」と思われる方もいらっしゃるかもしれませんが、Windows の世界ではボタンもテキスト入力エリアもチェックボックスなどもすべて「ウインドウ」の1種類なのです。
試しに CreateWindow() の最初の引数である "button" を "EDIT" と書き換えてコンパイル後に実行をしてみると、あら不思議。ボタンがテキスト入力エリアに変わってしまいます(笑)。← あくまで「お遊び」ですけどね。

Edit on Window

第2引数はボタンの上に書かれる文字列を定義します。ここを変えることでボタンにいろいろな文字列を表示させることができます(「はい」「いいえ」などが代表的でしょうか?)。
| でつながれた第3引数はちょっとややこしいので今回説明はパスします。
第4引数から始まる4つの数字はそれぞれボタンの位置(xとy座標)およびボタンのサイズ(横幅、高さ)です。この数値をいろいろ変えてボタンがどのような位置にどのような大きさで表示されるか見てみるのもおもしろいでしょう。
それ以降の引数は第3引数と同じく、今回説明を行なうのはパスします(結構難しいので)。

という感じで、今回は何もないウインドウの上にボタンをつける方法を書いてみました。
次回はこのボタンが押された時にどのようなことをすればいいのかを考えてみたいと思います。

prev next


戻る