メニューで本格的に!

今回は題名通りに、メニューをつけてみたいと思います。 メニューをつけるとやっと本格的なプログラムになってきた気がしますね。 メニューはリソースの一部なので、アイコンやカーソルと同じようにして作成します。 以下のチュートリアルで作っていきます。
  1. メニューリソース作成
  2. ウィンドウクラスにメニューを登録
  3. メニューのコマンドの処理を作成


1:メニューリソース作成

ではまず、「リソースビュー」を開き、右クリックメニューを開きます。そして「挿入」を選んでください。 いつものようにダイアログが出ますね、そして[MENU]を選んで作成します。



できたメニューを右クリックし、「プロパティ」を選んでリソースIDを[IDR_MENU]に変更してください。 ここは好きな名前でかまいません。



では早速メニューを作っていきましょ。適当にダブルクリックするとダイアログが開きます。 「ポップアップ」を解除してから、下の図のように入力してください。IDはメニューのID、キャプションは表示される文字列です。 キャプション内の[&Q]とはメニューアクセスキーと呼び、メニューを開いてから[Q]キーを押すとそのメニューが開かれるというものです。 また[Alt+Q]キーですぐにそこにアクセスできたりします。



リターンキーなどでダイアログを消すとコマンドが入り、メニューを作成できました。 今まで作ったリソースは下の図のようになっています。カーソルはなくてもOKです。



さて、メニューが作れたところでちょっとメニューの名前を確認しておきます。 基本的にはメニューの項目を「メニューアイテム」といいます、また下のテーブルを見ておいてください。
一番上のメニュー「メニューバー」「トップレベルメニュー」
メニューを押すと出てくるメニュー「サブメニュー」「ポップアップメニュー」「ドロップダウンメニュー」
右クリックメニューなどメニューバー以外のメニュー「ショートカットメニュー」「コンテキストメニュー」
アプリケーションのアイコンやタイトルバーを
右クリックしたときに出てくるメニュー
「ウィンドウメニュー」「システムメニュー」「コントロールメニュー」
サブメニューを開くメニューアイテム「メニュー名」
押すと何かが実行されるメニューアイテム「コマンド」「コマンドアイテム」

いろんな名前のメニューがありますが、要は「コマンド」の為にあることが分かればOKです。

2:ウィンドウクラスにメニューを登録

リソースを作成したので、次はソースコードを改造してウィンドウにメニューをつけます。 変更点はいつも通り赤くなってます。またいつもより省略してるところを増やしてます。


・・・

///// WinMain

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
	// ウィンドウクラスの登録
	WNDCLASSEX wcx;
	wcx.cbSize			= sizeof(WNDCLASSEX);
	wcx.style			= CS_DBLCLKS; // ダブルクリック検知
	wcx.lpfnWndProc		= WindowProc;
	wcx.cbClsExtra		= 0;
	wcx.cbWndExtra		= 0;
	wcx.hInstance		= hInstance;
	wcx.hIcon			= (HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_ICON)
							,IMAGE_ICON  , 0, 0,LR_DEFAULTCOLOR); // アイコン
	wcx.hIconSm			= (HICON)LoadImage(hInstance,MAKEINTRESOURCE(IDI_ICON)
							,IMAGE_ICON  ,16,16,LR_DEFAULTCOLOR); // 小さいアイコン
	wcx.hCursor			= (HCURSOR)LoadImage(hInstance,MAKEINTRESOURCE(IDC_CURSOR)
							,IMAGE_CURSOR, 0, 0,LR_DEFAULTCOLOR); // カーソル
	wcx.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1); // ウィンドウ背景色
	wcx.lpszMenuName	= MAKEINTRESOURCE(IDR_MENU); // メニューID
	wcx.lpszClassName	= strClassName;

	if(!RegisterClassEx(&wcx)) return 0; // クラス登録

	// ウィンドウ作成

・・・

ウィンドウクラスのwcx.lpszMenuNameメンバにメニューのリソースIDをいつも通りMAKEINTRESOURCEマクロで文字列に変換してます。 リソースIDは大体文字列に変換して使うのでこの使い方は覚えちゃってください。



ここまで来ていったんビルドしてみると、ちゃんとメニューがついています。ついてない人はどこか失敗してます。 でもこのメニューをクリックしても何にも起きません。理由はインプリメント(実装)していないからです。 分かりやすく言うと押したときにどうするかを書いていないからです。

3:メニューのコマンドの処理を作成

では早速、メニューコマンドを実装してみましょう。 今回二回目のソースコードです。ウィンドウプロシージャを改造しています。


・・・
上はWinMain関数です。

///// ウィンドウプロシージャ

LRESULT CALLBACK WindowProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
	switch(msg)
	{
///// コマンド系
	case WM_COMMAND:
		{
			// メニューコマンド振り分け
			switch(LOWORD(wp))
			{
			case IDM_QUIT: // 「終了」を押すとここ!
				PostMessage(hwnd,WM_CLOSE,0,0); // WM_CLOSE発信
				break;
			default: break;
			}
		}
		break;

///// 作成・破棄系
	case WM_CREATE:
		{
		}
		break;
	case WM_CLOSE:
		{
			// 終了確認
			if(MessageBox(hwnd,"終了しますか?","終了確認",MB_YESNO|MB_ICONQUESTION)==IDNO) break;
			DestroyWindow(hwnd); // DefWindowProcを通していないので自分でウィンドウを破棄。
		}
		break;
	case WM_DESTROY:
		{
			PostQuitMessage(0); // WM_QUIT送信
		}
		break;

///// デフォルト
	default: return DefWindowProc(hwnd,msg,wp,lp);
	}
	return 0;
}

///// End of Source

DownLoad!サンプルソースファイルをDownLoad!

説明します。メニューコマンドをくりっくすると「WM_COMMAND」というメッセージが送られてきます。 そのとき一緒に送られてきたwpの下位バイト(wpは2バイトでできていて、下の方の1バイト)にメニューID、つまり「IDM_QUIT」などが入っているわけです。 つまりLOWORDマクロ(下位バイトを取り出します)でメニューIDを取り出しswitchで振り分ければ、メニューコマンドごとに処理を記述出来るわけです。

ここでは「終了」を押して「IDM_QUIT」が来たときに、PostMessage関数を使っています。 この関数はその名の通りメッセージを発信する関数です。ここではhwnd(自分自身)に対して「WM_CLOSEメッセージ」を発信しています。 あとの二つのパラメータはwpとlpです。WM_CLOSEには必要ないので0にしています。 メッセージや関数が気になるときは、その上にカラットを置きF1キーを押すとヘルプが見れます。 ほとんど全てヘルプに書いてあるので気になったらすぐ見る習慣を付けてくださいね。

さて、ひとまずメニューがついたでしょうか?そして理解できたらありがとう(^_^;) 次回は「メニュー其の二」「アクセラレータ」をやってみます。アクセラレータといっても簡単なのでまた来週。


★INDEX★

Copyright(C) へぽぽ