現在來看看CreateDialog(),它是DialogBox()的姐妹函數.區別在於DialogBox()擁有自己的消息循環並且直到對話框關閉才返回,CreateDialog()則更加像CreateWindowEx()創建的一個窗口,立即返回並向你的消息循環發送消息,就像是你的主窗口發的消息樣.這就是所謂的無模態,而DialogBox()創建的是模態對話框.
創建的資源如下:
[cpp]
IDD_TOOLBAR DIALOGEX 0, 0, 98, 52
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
EXSTYLE WS_EX_TOOLWINDOW
CAPTION "My Dialog Toolbar"
FONT 8, "MS Sans Serif"
BEGIN
PUSHBUTTON "&Press This Button",IDC_PRESS,7,7,84,14
PUSHBUTTON "&Or This One",IDC_OTHER,7,31,84,14
END
你可以看到資源編輯器把DIALOG換成了DIALOGEX表明我們要為我們的對話框設置擴展風格.
接下來想在程序運行的時候創建對話框,想要對話框可視,所以在WM_CREATE的消息處理中創建它.我們也需要聲明一個全局變量來保持從CreateDialog()返回的窗口句柄以便在後面使用它.DialogBox()不向我們返回句柄因為DialogBox()在窗口銷毀的時候才返回.
[cpp] view plaincopyprint?
HWND g_hToolbar = NULL;
case WM_CREATE:
g_hToolbar = CreateDialog(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_TOOLBAR),
hwnd, ToolDlgProc);
if(g_hToolbar != NULL)
{
ShowWindow(g_hToolbar, SW_SHOW);
}
else
{
MessageBox(hwnd, "CreateDialog returned NULL", "Warning!",
MB_OK | MB_ICONINFORMATION);
}
break;
要檢查返回值,這什麼時候總是一個好的習慣,如果是正確的(不為NULL)我們就用ShowWindow()來顯示這個窗口,要是用DiaglogBox(),這一步就是不必要的,因為系統為我們調用了ShowWindow().
現在我需要為工具欄寫一個對話過程.
[cpp]
BOOL CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_PRESS:
MessageBox(hwnd, "Hi!", "This is a message",
MB_OK | MB_ICONEXCLAMATION);
break;
case IDC_OTHER:
MessageBox(hwnd, "Bye!", "This is also a message",
MB_OK | MB_ICONEXCLAMATION);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
大多數適用於DialogBox()的消息處理規則也適用於CreateDialog(),不調用DefWindowProc(),對不處理的消息返回FALSE,處理的返回TRUE.
有個攺變就是不為無模態窗口調用EndDialog(),可以像對常規的窗口一樣調用DestroyWindow().在主窗口的WndProc()中這樣寫...
[cpp]
case WM_DESTROY:
DestroyWindow(g_hToolbar);
PostQuitMessage(0);
break;
還有一點,希望在任何時候顯示或隠藏我們的工具欄,所以我在菜單上加上了兩個命令來做這件事情,並這樣處理:
[cpp] view plaincopyprint?
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_DIALOG_SHOW:
ShowWindow(g_hToolbar, SW_SHOW);
break;
case ID_DIALOG_HIDE:
ShowWindow(g_hToolbar, SW_HIDE);
break;
//... other command handlers
}
break;
如果在此時運行你的程序並試圖在兩個按鈕間切換的話,就會注意到不行,按Alt+P和Alt+O來激活按鈕都不行.為什麼? 因為DialogBox()有自己的消息循環並默認地處理這些事件,CreateDialog()卻沒有.但是可以通過在消息循環中調用可以為做默認處理的IsDialogMessage()來自己處理它們.
[cpp]
while(GetMessage(&Msg, NULL, 0, 0))
{
if(!IsDialogMessage(g_hToolbar, &Msg))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
這裡我們首先將消息傳給IsDialogMessage(),如果消息是為工具欄的(由我們傳進的窗口的句柄來指示),系統就作默認的處理並返回TRUE.這種情況下消息已經被處理了所以我們不需要再調用TranslateMessage()或DispatchMessage()了.如果消息是為另外一個窗口就照常處理.
值得提出來的是IsDialogMessage()也可以用於不是對話框的窗口來給它們一些像對話框的功能.記住,對話框就是一個窗口,並且大多數(如果不是全部的話)對話框的API可以工作於任何窗口.
貼個完整的代碼吧 有點長:
資源文件的建立如上。
[cpp]
#include <windows.h>
#define IDD_TOOLBAR 101
#define IDC_OTHER 9003
#define IDC_PRESS 9004
#define ID_DIALOG_SHOW 9005
#define ID_DIALOG_HIDE 9006
HWND g_hToolbar = NULL;
const char g_szClassName[] = "myWindowClass";
BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_PRESS:
MessageBox(hwnd,"you press a button!","this is message",MB_OK | MB_ICONINFORMATION);
break;
case IDC_OTHER:
MessageBox(hwnd,"you press a other button!","this is message",MB_OK | MB_ICONINFORMATION);
case IDOK:
EndDialog(hwnd, IDOK);
break;
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
HMENU hmenu,hSubMenu;
hmenu = CreateMenu();
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu,MF_STRING,ID_DIALOG_SHOW,"&Show");
AppendMenu(hSubMenu,MF_STRING,ID_DIALOG_HIDE,"&Hide");
AppendMenu(hmenu,MF_STRING | MF_POPUP,(UINT)hSubMenu,"&Dialog");
SetMenu(hwnd,hmenu);
g_hToolbar = CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_TOOLBAR),hwnd,AboutDlgProc);
if(g_hToolbar != NULL)
ShowWindow(g_hToolbar,SW_HIDE);
else
MessageBox(hwnd,"CreateDialog return NULL","Warning",MB_OK | MB_ICONINFORMATION);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_DIALOG_SHOW:
ShowWindow(g_hToolbar, SW_SHOW);
break;
case ID_DIALOG_HIDE:
ShowWindow(g_hToolbar, SW_HIDE);
break;
}
break;
case WM_LBUTTONDOWN:
{
char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, szFileName, MAX_PATH);
MessageBox(hwnd, szFileName, "This program is:", MB_OK |
MB_ICONINFORMATION);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
DestroyWindow(g_hToolbar);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 400,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
if(!IsDialogMessage(g_hToolbar,&Msg))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
return Msg.wParam;
}