モードレス
ポップアップなダイアログ
さて、これまでのダイアログは「モーダルダイアログボックス」と呼ばれるものでした
ここでは、もう一方のモードレスダイアログボックスというものを紹介します
モードレスダイアログボックスは、比較的ポップアップに近いダイアログです
モーダルダイアログボックスは、EndDialog() 関数が呼び出されるまで
ウィンドウに制御が戻ることはないというものでした
しかし、ダイアログを表示しながら同時にウィンドウも操作したい場合や
ダイアログを表示しつづけたほうが、アプリケーションとして都合が良い場合もあります
モードレスダイアログは、モーダルと異なりウィンドウにフォーカスを戻せます
モードレスダイアログの基本的な概念は、モーダルダイアログと同じです
モードレスの場合は CreateDialog() 関数でダイアログを生成します
HWND CreateDialog(
HINSTANCE hInstance , LPCTSTR lpTemplate,
HWND hWndParent , DLGPROC lpDialogFunc
);
hInstance はリソースが格納されているモジュールのハンドルを
lpTemplate はダイアログの名前を指定します
hWndParent は、ダイアログを所有する親ウィンドウを指定します
lpDialogFunc は、ダイアログプロシージャのポインタを指定します
成功するとダイアログのハンドルが返り、失敗すると NULL が返ります
DialogBox() 同様に、この関数はマクロです
DialogBox() によるモーダルダイアログと異なり、この関数はすぐに制御を返します
しかし、これだけではモードレスダイアログボックスは実現できない
モードレスダイアログボックスは、ウィンドウ同様にデフォルトで不可視です
ShowWindow() 関数を用いるか、リソーススクリプトで WS_VISIBLE をしていしなければ
可視化されるまで、CreateDialog() を使ったあとでも表示されません
まだ問題があります、モードレスダイアログボックスは独自のメッセージキューを持ちません
つまり、アプリケーションのメッセージキューを介して送られるのです
ここで、メッセージを識別するには IsDialogMessage() を使います
BOOL IsDialogMessage(HWND hDlg , LPMSG lpMsg);
hDlg には、ダイアログのハンドルを
lpMsg は、調べるメッセージを格納している MSG 構造体へのポインタを指定します
この関数は、もしメッセージがダイアログに対するものであればそれを処理します
メッセージが処理された場合は 0 以外、そうでないなら 0 が返ります
ここで処理されたメッセージは TranslateMessage() や DispatchMessage() に渡してはいけません
注意しなければいけないのが、NULL 状態のダイアログのハンドルを
このような関数に渡さないよう、あらかじめ調べるなどの作業が必要です
また、モードレスダイアログは DestroyWindow() で破棄 します
破壊した後は、ダイアログのハンドルを NULL 状態にする必要があります
//リソーススクリプト
KITTY DIALOG 10 , 10 , 100 , 50
FONT 12 , "MS ゴシック"
STYLE WS_VISIBLE | WS_POPUPWINDOW
CAPTION "Magical nyan nyan TARUTO" {
CTEXT "Kitty on your lap" , 1 , 10 , 10 , 90 , 10
}
#include <windows.h>
HWND hdlg;
BOOL CALLBACK DialogProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
switch (msg) {
case WM_CLOSE:
DestroyWindow(hdlg);
hdlg = NULL;
return TRUE;
}
return FALSE;
}
LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_LBUTTONUP:
if (hdlg) return 0;
hdlg = CreateDialog(
(HINSTANCE)GetWindowLong(hwnd , GWL_HINSTANCE) ,
TEXT("KITTY") , hwnd , DialogProc
);
return 0;
}
return DefWindowProc(hwnd , msg , wp , lp);
}
int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
PSTR lpCmdLine , int nCmdShow ) {
HWND hwnd;
HACCEL haccel;
MSG msg;
WNDCLASS winc;
winc.style = CS_HREDRAW | CS_VREDRAW;
winc.lpfnWndProc = WndProc;
winc.cbClsExtra = winc.cbWndExtra = 0;
winc.hInstance = hInstance;
winc.hIcon = LoadIcon(NULL , IDI_APPLICATION);
winc.hCursor = LoadCursor(NULL , IDC_ARROW);
winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
winc.lpszMenuName = NULL;
winc.lpszClassName = TEXT("KITTY");
if (!RegisterClass(&winc)) return -1;
hwnd = CreateWindow(
TEXT("KITTY") , TEXT("Kitty on your lap") ,
WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
CW_USEDEFAULT , CW_USEDEFAULT ,
CW_USEDEFAULT , CW_USEDEFAULT ,
NULL , NULL ,
hInstance , NULL
);
if (hwnd == NULL) return -1;
while(GetMessage(&msg , NULL , 0 , 0)) {
if (hdlg && IsDialogMessage(hdlg , &msg)) continue;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (hdlg) DestroyWindow(hdlg);
return msg.wParam;
}
ダイアログが表示されている状態で、ウィンドウにフォーカスがあります
このように、ダイアログを表示したまま別の作業が行えます
クライアント領域をマウス左クリックするとダイアログが表示されますが
モーダルと異なりダイアログが表示された状態でも
WM_LBUTTONUP が送られてくる可能性があることを忘れてはいけません
このプログラムでは、hdlg が有効である場合はダイアログを作らないようにしています
CreateDialog()
HWND CreateDialog(
HINSTANCE hInstance , LPCTSTR lpTemplate,
HWND hWndParent , DLGPROC lpDialogFunc
);
ダイアログボックステンプレートリソースから、モードレスダイアログボックスを作成します
hInstance - リソースが入っているモジュールのハンドルを指定します
lpTemplate - ロードするダイアログボックステンプレートの名前を指定します
hWndParent - ダイアログボックスを所有するウィンドウのハンドルを指定します
lpDialogFunc - ダイアログボックスプロシージャへのポインタを指定します
戻り値 - ダイアログボックスのウィンドウハンドル。失敗すると NULL
IsDialogMessage()
BOOL IsDialogMessage(HWND hDlg , LPMSG lpMsg);
指定されたメッセージが指定されたダイアログボックスに対するものかどうかを判断し
そうである場合はメッセージを処理します
hDlg - ダイアログボックスのハンドルを指定します
lpMsg - チェックするメッセージを含むMSG 構造体へのポインタを指定します
戻り値 - メッセージが処理されたなら 0 以外、そうでなければ 0