Version 10.13
ポップアップメニューふたたび
「前回は」
『手抜きでした』
「……否定はしません。えーっと、前回の最後で触れたように、これから手
を加えるのはウィンドウプロシージャの関係だけ。他はほぼ固定かな」
『これだけの機能があればなんとかなるってことね』
「そういうこと。まぁうまくいかない部分があったら微調整は必要だけど、
でもそのくらいだから。で、今回はそのウィンドウプロシージャについて」
// ウィンドウプロシージャ。
LRESULT CALLBACK WndProc
( HWND p_hWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_DESTROY )
{
// ×ボタンが押されました。
PostQuitMessage( 0 );
return 0;
}
else if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == ID_MENU_TEST )
{
// ID_MENU_TEST メニュー。
OutputDebugString( "ID_MENU_TEST : 終了します。\n" );
PostQuitMessage( 0 );
return 0;
}
}
// 標準的な処理をします。
return DefWindowProc( p_hWnd, p_uiMessage, p_wParam, p_lParam );
}
「今はこんな感じだけど、ホントは良くない例です」
『良くないの?』
「 MFC みたいに、それぞれのメッセージ毎に別の関数にするのが理想。た
とえばこういうふうに」
// ウィンドウが閉じます。
LRESULT OnDestroy()
{
PostQuitMessage( 0 );
return 0;
}
// ID_MENU_TEST が選択されました。
LRESULT OnMenuTest
( HWND p_hWnd
, WPARAM p_wParam
, LPARAM p_lParam
)
{
OutputDebugString( "ID_MENU_TEST : 終了します。\n" );
PostQuitMessage( 0 );
return 0;
}
// ウィンドウプロシージャ。
LRESULT CALLBACK WndProc
( HWND p_hWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_DESTROY )
{
return OnDestroy();
}
else if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == ID_MENU_TEST )
{
return OnMenuTest( p_hWnd, p_wParam, p_lParam );
}
}
// 標準的な処理をします。
return DefWindowProc( p_hWnd, p_uiMessage, p_wParam, p_lParam );
}
『つまりメッセージとか ID とかごとに別の関数呼ぶんだ』
「そのままウィンドウプロシージャに書いちゃうと、ウィンドウプロシー
ジャがどんどん長くなっちゃうからね」
『質問!』
「はい火美ちゃん」
『 MSDN 見てるとそういうながーいウィンドウプロシージャがいっぱいある
んですけど』
「全部悪い例です」
『……ホントに悪いの?』
「断言はできないけど、でも悪いと思うよ。ひとつの関数が大きくなるとプ
ログラムが見にくくなるから。特にネストが深くなって右へ右へとずれてい
くと……」
『あー、それはちょっとヤダ』
「まぁ、普通の関数と違うから微妙な部分もあるんだけど、でもやっぱりし
ない方がいいと思うよ」
『もひとつ質問!』
「はい火美ちゃん」
『 OnMenuTest() の引数がいっぱいあるのはなんで? 使ってないのに』
「これは微妙かな。あとで ID_MENU_TEST の処理で LPARAM とかが必要にな
る可能性があるかもしれないから、とか」
『つまりあとの拡張性のため?』
「ひとつはね。あと、こういうふうに引数付きのを用意しておいて、同じ
WM_COMMAND 用関数が必要になったらコピペするとか」
『使い回し用かー、確かにメニューが増えたらこの関数もいっぱい作る、な
ら引数付きのを用意しておいてコピペしまくり、の方が楽ね』
「でも必要ない引数を渡すっていうのも良くない気もするし、微妙かもね。
さて、今回は Version 9.05 ( No.166 ) で使ったポップアップメニューと
同じものを作ってみます」
『右クリックメニューでってゆーのね』
「さて問題。右クリックしたときに送られてくるメッセージは?」
『 WM_RBUTTONUP !』
「……さらっと出てきたね」
『だってその号に書いてあるもん』
「あ、ホントだ。というわけで、このメッセージが送られてきた時の関数を
まず追加します」
// 右クリックされました。
LRESULT OnRButtonUp
( HWND p_hWnd
, WPARAM p_wParam
, LPARAM p_lParam
)
{
OutputDebugString( "右クリックされました。\n" );
return 0;
}
// ウィンドウプロシージャ。
LRESULT CALLBACK WndProc
( HWND p_hWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_DESTROY )
{
return OnDestroy();
}
if( p_uiMessage == WM_RBUTTONUP )
{
return OnRButtonUp( p_hWnd, p_wParam, p_lParam );
}
else if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == ID_MENU_TEST )
{
return OnMenuTest( p_hWnd, p_wParam, p_lParam );
}
}
// 標準的な処理をします。
return DefWindowProc( p_hWnd, p_uiMessage, p_wParam, p_lParam );
}
『ビルドして実行、右クリックっと。うん、〈右クリックされました。〉っ
て出た』
「では次に、この関数の中にポップアップメニューを表示する機能を追加し
ます」
// 右クリックされました。
LRESULT OnRButtonUp
( HWND p_hWnd
, WPARAM p_wParam
, LPARAM p_lParam
)
{
// 画面上のマウスカーソルの位置を取得します。
POINT stPoint;
GetCursorPos( &stPoint );
// メニューバーを読み込みます。
HMENU hMenuBar
= LoadMenu
( GetModuleHandle( NULL )
, MAKEINTRESOURCE( IDM_MAIN )
);
// サブメニューを取得します。
HMENU hSubMenu
= GetSubMenu( hMenuBar, 0 );
// ポップアップメニューを表示します。
TrackPopupMenu
( hSubMenu
, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON
, stPoint.x
, stPoint.y
, 0
, p_hWnd
, NULL
);
return 0;
}
『結構長い……』
「では次回に続きます」
『え”』
/*
Preview Next Story!
*/
『さくっと続くね』
「ホントは1回でまとめたいんだけどね」
『そういえば、毎週違う話って感じだよね』
「ひとつのことをずーっとやっても仕方ないし」
『そーゆーもん?』
「その方が詰まらないし」
『そんなんでいいのかな……』
「というわけで次回」
< Version 10.14 MFC との違い・ポップアップメニュー編 >
『につづく!』
「でもポップアップメニューとか面白いでしょ?」
『そういうのでいいのかな……』