Version 8.09
ダイアログを閉じてみる
「今回はいよいよ、ダイアログを閉じられるようにします」
『やっと、やっとね……今まであの押したくもない【デバッグの中止】ボタ
ンを何度押すハメになったことか……』
「確かにあれは押したくないね……でも、ボタン押したときにどうこうって
いうのはちょっと難しいから、まずはちょっと変な方法で閉じてみます」
『変?』
「ダイアログプロシージャをこう書き換えて」
// ダイアログプロシージャ。
BOOL CALLBACK DialogProc
( HWND p_hDlgWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_MOUSEMOVE )
{
if (
( LOWORD( p_lParam ) == 0 )
&&
( HIWORD( p_lParam ) == 0 )
)
{
EndDialog( p_hDlgWnd, 100 );
}
return TRUE;
}
return FALSE;
}
『???』
「マウスカーソルが 0, 0 に来た時にダイアログが閉じるっていう」
『変! 変すぎ!』
「そ、そう?」
『なんかゲームみたい……それにやってみても閉じないし!』
「あ、マウスカーソルの位置はクライアントエリアのが返ってくるから」
『ってことはタイトルバーの下で、フレームの内側ね……あっ閉じた。やっ
ぱゲームね』
「クライアントエリアについては Version 7.02 ( No.122 ) を参照。で、
ここで重要なのは」
『 EndDialog() だよね。これでダイアログを閉じるの?』
「そう、この API で、第1引数に渡したウィンドウを閉じます」
『第2引数は?』
「この第2引数、実は DialogBox() の戻り値になるんです」
『そういえば全然触れてなかったね』
「 WinMain() の最後の return 0; でブレークポイントかけて」
『 iRet の値、ちゃんと 100 になってるね』
「これは実はちゃんとした使い道があるから、あとでそれを説明するね」
『ってゆーか、早くちゃんとボタンで閉じさせてよ!』
「じゃ、ダイアログプロシージャをこう書き換えて」
// ダイアログプロシージャ。
BOOL CALLBACK DialogProc
( HWND p_hDlgWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == IDOK )
{
// OK ボタンが押されました。
EndDialog( p_hDlgWnd, IDOK );
return TRUE;
}
}
return FALSE;
}
『うお、 if が2重!』
「あとのことを考えてね」
『まず WM_COMMAND ってメッセージを拾うのね』
「このメッセージはその名の通り〈コマンド〉、ボタンが押されたりメ
ニューが選択されたりしたときに呼ばれます」
『便利そうな、そうじゃないような……』
「ま、ダイアログとの時はメニューないし、メニューある時はダイアログ
じゃないからそんなに気にする必要はないかな」
『で、また例によって WPARAM にはふたつの値がくっついて入ってるわけ
ね』
「 HIWORD には【通知コード】っていうのが入ってくるんだけど今回は使わ
ないからパス。 LOWORD には、押されたボタンの ID が入ってます」
『……ああ! そっか、ダイアログエディタでボタンに付けた ID !』
「そうだ、実行してキャンセルボタン押してみて」
『うん、効かないね。でも OK ボタンを押せば、ダイアログが閉じる!』
「このチェックを内側の if でしてるってこと」
『この仕組みを使えば、どのボタンを押したときにどの処理をする、ってい
うのを変えられるわけね……』
「そう。実際……もう一度実行して、右上の閉じるボタン押してみて」
『反応しないね』
「実はこのボタンを押すとキャンセルボタンを押したときと同じ状態になる
から」
『そっか、キャンセルボタンを押したときにも閉じるようにしなきゃいけな
いんだ』
「というわけで」
// ダイアログプロシージャ。
BOOL CALLBACK DialogProc
( HWND p_hDlgWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == IDOK )
{
// OK ボタンが押されました。
EndDialog( p_hDlgWnd, IDOK );
return TRUE;
}
else if( LOWORD( p_wParam ) == IDCANCEL )
{
// キャンセルボタンが押されました。
EndDialog( p_hDlgWnd, IDCANCEL );
return TRUE;
}
}
return FALSE;
}
『おおっ、これならキャンセルボタンもペケボタンでも閉じられる!』
「この辺は普通に IDCANCEL にも対応させればいいだけだね」
『でもさ、これってちょっと無駄じゃない? 内側のふたつの if って一緒
にできそうだけど』
「してもいいし、しなくてもいいし。普通は OK とキャンセルって処理違う
でしょ」
『あ! そっか、 IDOK の方は更新を反映させたりして、 IDCANCEL の方は
何もせずに閉じる、ってすればいいんだ』
「これで、ボタンそれぞれの処理に対応できるわけ。でも、これもしなくて
もいいんだよね」
『しなくてもいい?』
「 EndDialog() の解説で、第2引数が DialogBox() の戻り値になるって
言ったでしょ。これを使えばいいわけ」
// WinMain() 。
int WINAPI WinMain
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
int iRet
= DialogBox
( p_hInstance
, MAKEINTRESOURCE( IDD_MAIN )
, NULL
, DialogProc
);
if( iRet == IDOK )
{
OutputDebugString( " OK が押されました。\n" );
}
else if( iRet == IDCANCEL )
{
OutputDebugString( "キャンセルが押されました。\n" );
}
return 0;
}
『 EndDialog() に IDOK を渡すか IDCANCEL を渡すかを変えれば、それが
DialogBox() の戻り値になるからそれをチェックすればいいわけね〜』
「どっちかって言うとこっちの方が一般的かな。 MessageBox() はこの方法
だし、 CDialog::DoModal() もこの方法」
『 CDialog::DoModal() は Version 5.30 ( No.095 ) でやったね』
「 CDialog の方はダイアログプロシージャ側での処理もできるけどね」
『ってゆーか、どっちがいいの?』
「場合によりけりだけど、便利なのはダイアログプロシージャ側で処理する
方」
『なんで?』
「場合によってはダイアログを閉じさせたくない時ってあるからね。値が間
違ってたとか」
『そっか、ダイアログプロシージャなら、 EndDialog() を呼ばなきゃダイ
アログ閉じないけど、 DialogBox() の戻り値の方だと、もうダイアログ閉
じちゃってるからどうしようもないんだ』
「一番いけないのは処理を両方に分散させることかな。そういうことすると
混乱の元だから」
『バグの温床?』
「そゆこと」
/*
Preview Next Story!
*/
『ダイアログ閉じるだけでもひと苦労ねー』
「メッセージ関係は MFC 使わないとかなり面倒かもね」
『ってことはさらに面倒に?』
「そう、特に通知メッセージ関係はね」
『つうちめっせーじ?』
「というわけで次回」
< Version 8.10 コマンドと通知メッセージ >
『につづく!』
「実際、この辺がなんとかなれば MFC なんて使わずに済むのに」
『…… MFC って悪者なの?』
「ぎく」