一提到對話框,相信對它熟悉的人不在少數,更不用說碼農們了,你可能會問,對話框和窗口有什 麼區別嗎?本質上是沒有區別的,對話框也是一種窗口(前面也說過,控件也可視為子窗口)。
最簡單的對話框要數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; }