Section.3にて作成した、Hello Worldに、リソースとして、メニューバーとアイコンを追加してみよう。この辺から、コンパイルにはMAKEFILEを利用した方が便利だろう。BC PADを利用されている方も、MAKEFILEを使えば、コンパイルが簡単になる。
- メニューのデザイン
Windowsアプリには、大抵メニューバーが付いている。タイトルバーの下に、
等と表示されるあれだ。ここで示すのはサンプルだし、Hello World!なので、メニューに凝った事は出来ないが、とりあえず、以下のメニューを用意し、リソースファイル(test002.rc)に記述する。
因みに、[開く]はダミーとして、MessageBoxにて、ダイヤログ表示するのみとする。
test002.rc/メニュー部分
//メニュー
samp_menu MENU DISCARDABLE
{
POPUP "ファイル(&F)" {
MENUITEM "開く(&O)" IDM_OPEN
MENUITEM "終了(&X)" IDM_EXIT
}
POPUP "ヘルプ(&H)" {
MENUITEM "バージョン表示(&A)", IDM_ABOUT
}
}
|
メニューのリソースは、上記の様に記述する。とりあえず、メニューの内容を変えたり、グレーアウト等の特殊な制御をしないのであれば、上記のフォーマットを真似して書けば良いだろう。気を付けなければならない箇所は、最初にメニュー名(ここでは、samp_menu)を記述する事と、MENUITEMと、メッセージID(IDM_OPEN,IDM_EXIT等)を1対1で記述する事である。
- メニュー名(samp_menu)は、WinMainの中で、WNDCLASSのパラメータにセットする。
→後で説明
- メッセージIDは、RESOURCE.hに定義して、メインのプログラムにインクルードする。
→後で説明
※メニューへのショートカットは、アルファベットの前に、&を付ける事で記述出来る。例えば「ファイル(&F)」で記述すれば、[ALT]+[F]にて、ファイルメニューに移行出来る。
- アイコンのインクルード
Windowsのアプリであれば、アイコンを付けておきたいと思うのが普通だろう,アイコンもリソースとして、アプリに簡単に貼り付ける事が出きる。 ←こんなイメージ
test002.rc/アイコン部分
//アイコン
samp_icon ICON test002.ico
|
アイコンのリソースは、
アイコン名 ICON アイコンファイル名
の様に記述すれば良い。アイコン名は、メニュー名と同様に、WinMainの中で、LoadIcon関数を介してWNDCLASSのパラメータにセットする。→後で説明
- リソース・ヘッダファイルの書き方
リソースファイルと、メインの実行プログラムを関連付ける為に、リソースのヘッダファイルを記述し、リソースファイル(test002.rc)と、メインプログラム(ここではtest002.cpp)にインクルードしておく。
resource.h
#define IDM_OPEN 101
#define IDM_EXIT 102
#define IDM_ABOUT 999
|
リソース・ヘッダの中身は、メニューで定義した、メッセージIDの数値宣言である。この他、ダイヤログをリソースで定義する場合は、そこに配置するボタンやオブジェクトのIDも存在するので、ここで数値宣言を行わなければならない。
数値宣言は、ユーザが行うのであるが、注意すべき点は,
- 同じ数値を採るIDが存在しない事(全部違う数値を割り当てる事)
- 100以下の数値は、システムが使う(らしい)ので、使ってはいけない事
である。
ソースのダウンロード
↑試してみたい人は、ここからダウンロード
- コンパイルの方法及び実行
基本的に分割コンパイルでは無いが、今回は、リソース部分のコンパイル,リンクも行うので、makeファイルを用意した。従って、MS-DOSプロンプトで、作業ディレクトリに移動して、
MAKE
を実行すれば良い。BC PADを使っている場合は、該当フォルダで何れかのファイルを読み込んで、[実行]→[make]を実行すれば良い。
問題無ければ、test002.exeが生成される筈である。エクスプローラ上で、実行ファイルが定義したアイコンで表示されているだろうか?そのまま実行すれば、前項で作成した、Hello World!に、メニュー表示が追加されたものが表示される筈である。
- ソースの説明
前回のサンプル(test001.cpp)から、変更の有った部分についてのみ説明する。
- WinMain関数
アイコンとメニューを追加しているので、WNDCLASSに「このアイコンを使うよ」という部分と、「メニューはこれです」という事を追加して、RegisterClass()関数にて宣言する必要が有る。
下記は抜粋
.............
wc.hInstance = hInstance ;
wc.hIcon = LoadIcon(hInstance,"samp_icon") ;
wc.hCursor = LoadCursor(NULL,IDC_ARROW) ;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH) ;
wc.lpszMenuName = "samp_menu" ;
wc.lpszClassName = "HelloWorld" ;
....................
|
太字部分が追加された部分である。また、赤字で示した部分は、リソースファイルに定義した、アイコン名,メニュー名と同じものを記述しなければならない。
- WndProc関数
前項でも少し触れた通り、メニューを追加したので、メニューを選択された場合のイベントに対する処理を記述しなければならない。
下記は抜粋
..............
case WM_PAINT: BeginPaint(hwnd,&ps) ;
TextOut(ps.hdc,0,0,"Hello World!",12) ;
EndPaint(hwnd,&ps) ;
break ;
case WM_COMMAND:
switch(wParam){
case IDM_OPEN:
MessageBox(hwnd,"ダミー","Dummy",MB_OK) ;
break ;
case IDM_EXIT: PostMessage(hwnd,WM_CLOSE,0,0) ;
break ;
case IDM_ABOUT: MessageBox(hwnd,
"Hello World test 002",
"このプログラムについて",
MB_OK) ;
break ;
default:
return DefWindowProc(hwnd,msg,wParam,lParam) ;
}
break ;
default: return DefWindowProc(hwnd,msg,wParam,lParam) ;
..................
|
太字部分が追加された部分である。また、赤字で示した部分は、リソースファイル,リソース・ヘッダに定義した、メッセージIDと同じものを記述して、対応する処理を記述する。
- PostMessageについて
色々なサンプルで同様に使われているので、そのまま流用してしまったが、動作内容については不明である。多分、内部割り込みの様に使用しているのだと思うが、推測の域を出ない,推測が正しければ、PostMessageで、WM_CLOSEのイベントを発生させる事により、Windowsアプリをクローズさせ、WM_DESTROYのイベントが発生しているのだと考えられる。
サンプルのソースコード
|