モーダルダイアログボックス
モーダルダイアログとモードレスダイアログボックス
ここでは、重要なリソースである、ダイアログボックスについて説明します。ダイアログボックスのダイアログとは、対話という意味である。その名のとおりダイアログボックスは、コンピュータと情報のやり取りをする場合に使用されるウインドウのことを指します。
ダイアログボックスは大きく分けると、モーダルダイアログボックスとモードレスダイアログボックスに分類されます。モーダルダイアログボックスは、ダイアログボックスを閉じるまでは同じアプリケーションの他のウインドウにフォーカスを移動できません。それに対し、モードレスダイアログボックスは、ダイアログボックスを閉じなくても、他のウインドウにフォーカスを移動できます。
ここではまず、手始めにモーダルダイアログボックスの使い方について説明します。
サンプルプログラム
まずは、以下のサンプルを入力し、指示に従って、新しいリソースを追加してから実行してみてください。
win32exproj4-1:WinMain.cpp// ************************************ // Ex モーダルダイアログ // ************************************ //必要なヘッダーファイルのインクルード #define STRICT #include <windows.h> #include <stdlib.h> #include <string.h> #include <tchar.h> // リソースの読み込み #include "resource.h" // シンボル定義及びマクロ #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 // インスタンス(グローバル変数) HINSTANCE hInst; // ウィンドウプロシージャのコールバック関数 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK DlgWndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { static TCHAR szWindowClass[] = _T("Sample04"); static TCHAR szTitle[] = _T("モーダルダイアログのサンプル"); WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("RegisterClassExの処理に失敗しました"), _T("Sample03"), NULL); return 1; } hInst = hInstance; // グローバル変数に値を入れる // The parameters to CreateWindow explained: // szWindowClass : アプリケーションの名前 // szTitle : タイトルバーに現れる文字列 // WS_OVERLAPPEDWINDOW : 生成するウィンドウのタイプ // CW_USEDEFAULT, CW_USEDEFAULT : 最初に置くポジション (x, y) // WINDOW_WIDTH, WINDOW_HEIGHT : 最初のサイズ (幅, 高さ) // NULL : このウィンドウの親ウィンドウのハンドル // NULL : メニューバー(このサンプルでは使用せず) // hInstance : WinMain関数の最初のパラメータ // NULL : WM_CREATE情報(このアプリケーションでは使用せず) HWND hWnd = CreateWindow( szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL ); // ウィンドウが生成できなかった場合 if (!hWnd) { MessageBox(NULL, _T("ウィンドウ生成に失敗しました!"), _T("Sample04"), NULL); return 1; } // ウィンドウの表示に必要なパラメータ: // hWnd : CreateWindowの戻り値 // nCmdShow : WinMainの引数の4番目 ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // メインのメッセージループ: MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } // ウィンドウプロシージャ(メッセージに対するコールバック関数) LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { //ポイント構造体 POINT pt; switch (message) { //キーを押した case WM_KEYDOWN: switch(wParam) { case VK_ESCAPE: //終了メッセージを発生させる PostMessage(hWnd, WM_CLOSE, 0, 0); break; } break; //ウインドウが生成されたときに1度だけ通過 case WM_CREATE: break; //マウス右クリック case WM_RBUTTONDOWN: pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); //クライアント座標をスクリーン座標へ変換 ClientToScreen( hWnd, &pt); //ポップアップメニューを表示 TrackPopupMenu( GetSubMenu( GetMenu( hWnd ), 0), TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL); break; case WM_COMMAND: switch( LOWORD(wParam) ) { case ID_40001: //バージョン(A) MessageBox(hWnd, _T("メニューの実装Ver1.0"), _T("バージョン情報"), MB_OK); break; case ID_40002: //終了(X) PostMessage(hWnd, WM_CLOSE, 0, 0); break; case ID_40003: //モーダルダイアログボックスを作成 DialogBox( (HINSTANCE)GetWindowLong( hWnd, GWL_HINSTANCE), MAKEINTRESOURCE( IDD_DIALOG1 ), hWnd, (DLGPROC)DlgWndProc); break; } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); break; } return 0; } //-------------------------------------------- // Name:DlgWndProc() // Desc:ダイアログ用ウィンドウプロシージャ //-------------------------------------------- BOOL CALLBACK DlgWndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) { switch( iMsg ) { case WM_INITDIALOG: //ダイアログボックスが生成されたとき return TRUE; case WM_COMMAND: switch( LOWORD(wParam) ) { case IDCANCEL: //モーダルダイアログボックスを破棄 EndDialog(hWnd, 0); break; } return TRUE; default: return FALSE; } }
リソースの作成
リソースは、メニュー、IDR_MENU1を追加し、メニューの項目を以下のように入力します。(表4-1./図4-1.)
表4-1.IDR_MENU1のメニュー項目のIDとキャプションの組み合わせID | キャプション |
---|---|
ID_40001 | バージョン(&A) |
ID_40002 | 終了(&X) |
ID_40003 | ダイアログ(&D) |
図4-1.メニューリソースの中身
続いて、ダイアログリソースを追加します。他のリソースの時と同様、「リソースファイル」を右クリックし、[追加]→[リソース]を選択すると、以下のダイアログが出現するので、Dialogを選択してください。(図4-2.)
図4-2.ダイアログメニューの追加
すると、以下のように新規にダイアログが追加されます。(図4-3.)IDは、IDD_DIALOG1となっています。(図4-4.)
図4-3.追加されたダイアログリソース
リソースの設定が終われば、プログラムの実行が可能です。プログラムを実行すると、メニューのあるウィンドウが起動します。(図4-4.)
図4-4.追加されたリソースのID
以上で、リソースの追加は終了です。次は、実際にプログラムを動かしてみます。
プログラムの実行
メニューから「ファイル」を選ぶと、「ダイアログ(D)」という項目があるので、これを選択します。(図4-5.)
図4-5.「ダイアログ」メニューの選択
すると、ダイアログウィンドウが出現します。(図4-6.)
図4-6.ダイアログウィンドウの出現
ダイアログウィンドウが出現している間は、メインとなるウィンドウの操作はできません。ファイルダイアログの「キャンセル」ボタンを押すと、ダイアログウィンドウは消えます。すると、再びメインのウィンドウを操作することが可能になります。
プログラムの仕組み
ダイアログのプロシージャ
今回使用する、ダイアログボックスはウインドウと同じく、対応するウインドウのイベントを処理するプロシージャを用意してあげる必要があります。それが、24行目で宣言されているDlgWndProcプロシージャです。
ダイアログプロシージャダイアログの生成と消去
続いて、モーダルダイアログの生成と消去について説明します。モーダルダイアログは、DialogBox関数で出現させ、EndDialog関数で終了させます。各々の関数の仕様は、以下の通りです。
Dialogbox関数HINSTANCE hInstance, // モジュールのハンドル
LPCTSTR lpTemplate, // ダイアログボックステンプレート
HWND hWndParent, // オーナーウィンドウのハンドル
DLGPROC lpDialogFunc // ダイアログボックスプロシージャ
);
resource.hで設定してあるアイコン識別子を設定してあげることで、作成したダイアログボックスを使用できます。今回の識別子はIDD_DIALOG1で、プロシージャがDlgWndProcなので、149行目から158目のように実装します。ID_40003は、メニューの項目「ダイアログ(D)」に対応しているため、メニューでこの項目が選択されると、この箇所が実行され、モーダルダイアログが出現します。
Dialogbox関数の実装//モーダルダイアログボックスを作成
DialogBox(
(HINSTANCE)GetWindowLong( hWnd, GWL_HINSTANCE),
MAKEINTRESOURCE( IDD_DIALOG1 ),
hWnd,
(DLGPROC)DlgWndProc);
break;
}
尚、モジュールのハンドル(インスタンスハンドル)はGetWindowLong関数 を使用することで、ウインドウハンドルから取得しています。
EndDialog関数HWND hDlg, // ダイアログボックスのハンドル
INT_PTR nResult // 返したい値
);
この関数を呼び出しているのは、DlgWndProc関数の中です。(181行目~189行目)ダイアログの「キャンセル」ボタンを押すと、WM_COMMANDメッセージが発生し、コマンドの種類がIDCANCELであることから、ここにそのイベント処理を記述します。
Dialogbox関数の実装switch( LOWORD(wParam) )
{
case IDCANCEL:
//モーダルダイアログボックスを破棄
EndDialog(hWnd, 0);
break;
}
return TRUE;
これにより、ダイアログの「キャンセル」ボタンを押すと、ダイアログが終了します。