一提到對話框,相信對它熟悉的人不在少數,更不用說碼農們了,你可能會問,對話框和窗口有什么區別嗎?本質上是沒有區別的,對話框也是一種窗口(前面也說過,控件也可視為子窗口)。
最簡單的對話框要數MessageBox彈出來的對話框了,是吧?這個函數我有信心,大家都會用的,畢竟很簡單。
好的,廢話不多扯了,馬上開始本文第一件事,創建一個對話框。
對話框作為一種資源,它存放在資源文件中(.rc),如果項目中沒有rc文件,第一種方法是在“解決方案資源管理器”中在“資源文件”節點右擊,從菜單中選擇“添加”-“新建項”來加入一個rc文件。第二種方法,可以從VS的“視圖”菜單中打開“資源視圖”,在資源視圖中,在項目名節點上右擊,從菜單中找到“添加”-“資源”。

然后,選擇對話框,點新建按鈕。

在屬性窗口中為這個對話框名命一個ID,隨便你喜歡,我把它設為IDD_MYDLG。

OK,現在,我們就可以利用可視化設計器來玩了,看看,還不錯的,雖然沒有WinForm的設計器那么猛。
把默認兩個按鈕刪掉,我們從工具箱中拖放一些控件。記得為控件的ID命名,就像在WinForm里面要設置Name屬性一樣。
大概就這樣,拖一個Static Text和Button控件,隨后我們嘗試實現一個功能:點擊按鈕后,在靜態文本框中顯示文本。這個編輯器怎么用,就就不說了。

保存資源文件,下面我們開始寫代碼。
1、在主窗口的消息處理程序中響應WM_CREATE消息,用CreateDialog函數創建并顯示非模態對話框。
~~~
LRESULT CALLBACK WinMainProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM LParam)
{
HWND hdlg;
switch (msg)
{
case WM_CREATE:
?hdlg = CreateDialog(hgapp,MAKEINTRESOURCE(IDD_MYDLG),hwnd,(DLGPROC)DlgProc);
?if(hdlg)
?{
??//顯示對話框
??ShowWindow(hdlg, SW_NORMAL);
?}
?return 0;
case WM_DESTROY:
?PostQuitMessage(0);
?return 0;
default:
?return DefWindowProc(hwnd,msg,wParam,LParam);
}
return 0;
}
~~~
CreateDialog的最后一個參數是一個CALLBACK,這個和我們的WindowProc是一鳥樣的,注意在定義該函數時,一定要先在頭文件或源文件的前面聲明一下,不然到這里會找不到,通常我們會把這些函數都放到WinMain函數后面來寫,只是通常這樣,并不是說一定要這樣。
DlgProc如下:
~~~
// 處理對話框中的數據
INT_PTR CALLBACK DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
return (INT_PTR)FALSE;
}
~~~
和WindowProc一樣,也有一個DefDlgProc,但是這里最好不要調用,注意MSDN上關于這函數說明的最后一段話。
The DefDlgProc function must not be called by a dialog box procedure; doing so results in recursive execution.
如果在DialogProc中調用DefDlgProc會導致死循環。其實,我們為窗口寫的消息循環也是死循環,GetMessage是不斷執行,除非接到WM_QUIT消息讓它返回假(0)就跳出循環,而對于對話框,我們并沒有為它寫GetMessage,也不向它PostQuitMessage,它有可能會無法跳出循環。
現在,程序是可以運行的。

不過,無論你怎么操作,對話框還是沒返應,因為現在我們還沒處理相關消息。
當用戶操作系統菜單或者點擊標題欄的 最大化, 最小化 或 關閉 按鈕,都會收到WM_SYSCOMMAND消息,如果不響應WM_SYSCOMMAND,就會放到WM_COMMAND,但WM_COMMAND通常要處理控件的消息,故最好用WM_SYSCOMMAND消息。
2、在對話框的DlgProc中響應WM_SYSCOMMAND。
~~~
case WM_SYSCOMMAND:
if(wParam == SC_CLOSE)
{
// 如果執行了關閉
// 銷毀對話框,將收到WM_DESTROY消息
DestroyWindow(hdlg);
}
return 0;
~~~
3、我們已經知道響應按鈕單擊是處理WM_COMMAND。要改變靜態文本中的文本,一可以用?Static_SetText宏,二可以用SetWindowText,三可以發送WM_SETTEXT消息。但是,無論采用哪種方法,我們都得解決一個問題——怎么獲取到靜態文本控件的句柄。所以,認識一下這個函數:
~~~
HWND WINAPI GetDlgItem(
_In_opt_ HWND hDlg,
_In_ int nIDDlgItem
);
~~~
你猜都猜到了,參數一是對話框的句柄,參數二是要返回句柄的控件的ID。好,我們試試。
~~~
case WM_COMMAND:
{
if(LOWORD(wParam) == IDC_BTN)
{
nCount ++; //每點擊一次,就+1
// 獲取控件句柄
HWND hStatic = GetDlgItem(hdlg,IDC_DISP);
// 設置控件文本
WCHAR str[MAXCHAR];
// 格式化字符串
int n = wsprintf(str, L"你點擊了%d次按鈕。", nCount);
//在最后一個字符后加上結止符
str[n] = '\0';
SetWindowText(hStatic, str);
}
}
return 0;
~~~
現在來運行一下,每點擊一次按鈕,就會在靜態文本控件中顯示“你點擊了X次按鈕。

好,大功告成。
下面是完整的代碼清單。
~~~
#include <Windows.h>
#include "resource.h"
LRESULT CALLBACK WinMainProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM LParam);
INT_PTR CALLBACK DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
HINSTANCE hgapp; //當前應用程序句柄
int WINAPI WinMain(HINSTANCE hThisApp, HINSTANCE hPrevApp, LPSTR lpCmd, int nShow)
{
LPCWSTR cn = L"My";
WNDCLASS wc = {sizeof(WNDCLASS)};
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hInstance = hThisApp;
wc.lpfnWndProc = WinMainProc;
wc.lpszClassName = cn;
wc.style = CS_HREDRAW | CS_VREDRAW;
//注冊窗口類
RegisterClass(&wc);
//創建窗口
HWND hwnd = CreateWindow(cn,L"主窗口",WS_OVERLAPPEDWINDOW,
30,22,360,280,NULL,NULL,hThisApp,NULL);
if(!hwnd)
return 0;
hgapp = hThisApp;
//顯示窗口
ShowWindow(hwnd,nShow);
//更新窗口
UpdateWindow(hwnd);
//消息循環
MSG msg;
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WinMainProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM LParam)
{
HWND hdlg;
switch (msg)
{
case WM_CREATE:
hdlg = CreateDialog(hgapp,MAKEINTRESOURCE(IDD_MYDLG),hwnd,(DLGPROC)DlgProc);
if(hdlg)
{
//顯示對話框
ShowWindow(hdlg, SW_NORMAL);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd,msg,wParam,LParam);
}
return 0;
}
// 處理對話框中的數據
INT_PTR CALLBACK DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static int nCount = 0;//點擊按鈕的次數
switch(msg)
{
case WM_SYSCOMMAND:
if(wParam == SC_CLOSE)
{
// 如果執行了關閉
// 銷毀對話框,將收到WM_DESTROY消息
DestroyWindow(hdlg);
}
return 0;
case WM_COMMAND:
{
if(LOWORD(wParam) == IDC_BTN)
{
nCount ++; //每點擊一次,就+1
// 獲取控件句柄
HWND hStatic = GetDlgItem(hdlg,IDC_DISP);
// 設置控件文本
WCHAR str[MAXCHAR];
// 格式化字符串
int n = wsprintf(str, L"你點擊了%d次按鈕。", nCount);
//在最后一個字符后加上結止符
str[n] = '\0';
SetWindowText(hStatic, str);
}
}
return 0;
}
return (INT_PTR)FALSE;
}
~~~
- 前言
- (1):關于C++的幾個要點
- (2):完整的開發流程
- (3):窗口的重繪
- (4):創建菜單
- (5):具有單選標記的菜單
- (6):創建右鍵菜單
- (7):多邊形窗口
- (8):繪圖(A)
- (9):繪圖(B)
- (10):繪圖(C)
- (11):使用控件——先來耍一下按鈕
- (12):使用控件——單選按鈕
- (13):握手對話框
- (14):用對話框作為主窗口
- (15):ListView控件
- (16):ListView的多個視圖
- (17):啟動和結束進程
- (18):使用對話框的兩個技巧
- (19):瀏覽和打開文件
- (20):瀏覽文件夾
- (21):復制&amp;粘貼&amp;剪貼板操作
- (22):抓取屏幕
- (23):漸變顏色填充
- (24):計時器
- (25):監視剪貼板