11.2.1 模态与非模态对话框的区别
区别 |
模态 |
非模态 |
默认风格 |
WS_POPUP|DS_MODALFRAME |
WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_VISIBLE |
创建函数 |
DialogBox 创建后要等结束对话框后才返回。 |
CreateDialog 创建后立即返回 |
可见性 |
默认是可见的 |
得指定WS_VISIBLE,否则创建完后得调用ShowWindow |
消息处理 |
有自己的消息循环 |
消息进入程序的消息队列(处理见下面) |
销毁对话框 |
EndDialog |
①DestroyWindow(hDlgModeless); hDlgModeless =NULL; ②WM_CLOSE消息的处理(对话框窗口过程内部并不处理,得自己处理,如下) DestroyWindow(hDlgModeless) hDlgModeless =NULL; |
(2)将消息传递给对话框的窗口过程
①保存全局变量hDlgModeless (=CreateDialog…)
②消息循环的更改
while (GetMessage(&msg,NULL,0,0)) { //IsDialogMessage主要是处理对话框键盘导航(如Tab键转移焦点),注意是键盘消息,而不是鼠标消息 //鼠标消息时返回False,仍然会进入下列的转换和分派过程中去 if (hDlgModeless ==0 || !IsDialogMessage(hDlgModeless,&msg)) { if (!TranslateAccelerator(hwnd,hAccel,&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } }
11.2.2 新的COLORS程序
(1)滚动条ID分别为10、11、12,对应的当前值的静态文本字段ID分别为13、14、15
(2)主窗口样式包含WS_CLIPCHILDREN,表示不擦除对话框的情况下重绘主窗口
(3)设置颜色值:SetDlgItemInt(hDlg,nIDDlgItem,uValue, bSigned);
(4)一次CreateDialog会同时创建对话框上的子窗口控件
(5)IsDialogMessage主要处理对话框中的键盘导航消息
【COLORS2程序】
效果图:
/*------------------------------------------------------------ COLORS2.C -- Version using Modeless Dialog Box (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK ColorSrcDlg(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("Colors2"); HWND hwnd; MSG msg; WNDCLASSEX wndclass; HWND hDlgModeless; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = NULL;// LoadIcon(hInstance, szAppName); wndclass.hIconSm = NULL;// LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = CreateSolidBrush(0L); //黑色背景 wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("Color Scroll"), // window caption WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters hDlgModeless = CreateDialog(hInstance, TEXT("COLORSCRDLG"), hwnd, ColorSrcDlg); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { //IsDialogMessage主要是处理对话框键盘导航(如Tab键转移焦点),注意是键盘消息,而不是鼠标消息 if (!IsDialogMessage(hDlgModeless, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: DeleteObject((HGDIOBJ)SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)GetStockObject(WHITE_BRUSH))); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } BOOL CALLBACK ColorSrcDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static int iColor[3]; //用来记录各滚动条当前颜色值 HWND hCtrl, hwndParent; int iCtrlID, iIndex; switch (message) { case WM_INITDIALOG: for (iCtrlID = 10; iCtrlID < 13; iCtrlID++) { hCtrl = GetDlgItem(hDlg, iCtrlID); SetScrollRange(hCtrl, SB_CTL, 0, 255, FALSE); SetScrollPos(hCtrl, SB_CTL, 0, FALSE); } return TRUE; case WM_VSCROLL: hCtrl = (HWND)lParam; //滚动条句柄 hwndParent = GetParent(hDlg); iCtrlID = GetWindowLong(hCtrl, GWL_ID); iIndex = iCtrlID - 10; switch (LOWORD(wParam)) //通知码 { case SB_PAGEDOWN: iColor[iIndex] += 16; break; case SB_LINEDOWN: iColor[iIndex] += 1; break; case SB_PAGEUP: iColor[iIndex] -= 16; break; case SB_LINEUP: iColor[iIndex] -= 1; break; case SB_TOP: iColor[iIndex] = 0; case SB_BOTTOM: iColor[iIndex] = 255; case SB_THUMBPOSITION: case SB_THUMBTRACK: iColor[iIndex] = HIWORD(wParam); break; default: return FALSE; } iColor[iIndex] = max(0, min(255, iColor[iIndex])); SetScrollPos(hCtrl, SB_CTL, iColor[iIndex], TRUE); SetDlgItemInt(hDlg, iCtrlID + 3, iColor[iIndex], FALSE); DeleteObject((HGDIOBJ)SetClassLong(hwndParent, GCL_HBRBACKGROUND, (LONG)CreateSolidBrush(RGB(iColor[0], iColor[1], iColor[2])))); InvalidateRect(hwndParent, NULL, TRUE); return TRUE; case WM_COMMAND: break; } return FALSE; }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Colors2.rc 使用 // // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1004 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//Colors2.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Dialog // COLORSCRDLG DIALOGEX 16, 16, 181, 191 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION CAPTION "Color Scroll Scrollbars" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN SCROLLBAR 10, 28, 32, 20, 136, SBS_VERT | WS_TABSTOP SCROLLBAR 11, 77, 32, 20, 136, SBS_VERT | WS_TABSTOP SCROLLBAR 12, 126, 32, 20, 136, SBS_VERT | WS_TABSTOP CTEXT "&Red", IDC_STATIC, 33, 18, 14, 8, NOT WS_GROUP CTEXT "&Green", IDC_STATIC, 78, 18, 20, 8, NOT WS_GROUP CTEXT "&Blue", IDC_STATIC, 128, 18, 14, 8, NOT WS_GROUP CTEXT "0", 13, 30, 169, 15, 8, NOT WS_GROUP CTEXT "0", 14, 78, 169, 19, 8, NOT WS_GROUP CTEXT "0", 15, 125, 169, 22, 8, NOT WS_GROUP END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN "COLORSCRDLG", DIALOG BEGIN END END #endif // APSTUDIO_INVOKED #endif // 中文(简体,中国) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
11.2.3 HEXCALC:窗口还是对话框?
(1)一般对话框程序不能在VC的资源编辑器里设置/修改Class Name,对话框属性的ClassName为不可用状态。但可以通过稍作修改,来达到设置对话框Class Name的目的。
①在资源view中,右键单击*.rc,点属性,修改MFC Mode为false;
②在看对话框的属性设置中,Class Name属性已经变成可编辑的状态了,设置好Class Name后保存;
(2)该对话框的特殊之处——普通层叠窗口与非模态的混合体!
①窗口过程不是Windows内置,而是一个正常的窗口过程。(通过指定对话框的“类名”),该ClassName告诉Windows把消息发送到我们指定的窗口过程。
②在创建时调用CreateDialog
(3)注册窗口类时:cbWndExtra必须设DLGWINDOWEXTRA才能注册自己的对话框窗口过程。
(4)按钮的ID被设置成其显示文本对应的ASCII码
(5)焦点问题:每次单击按钮时,焦点总是设为父窗口。否则,焦点会停留在按钮上面,否则,焦点会停留在按钮上面,从而导致键盘消息失效。
【HexCalc程序】
效果图:
/*------------------------------------------------------------ HEXCALC.C -- Hexadecimal Calculator (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("HexCalc"); HWND hwnd; MSG msg; WNDCLASSEX wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = DLGWINDOWEXTRA; //对自定对话框窗口类必须这样设置! wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIconSm = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateDialog(hInstance, szAppName, 0, NULL); //对话框,却属于自己的窗口过程WndProc(非内置的!) ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } void ShowNumber(HWND hwnd, UINT iNumber) { TCHAR szBuffer[20]; wsprintf(szBuffer, TEXT("%X"), iNumber); SetDlgItemText(hwnd, VK_ESCAPE, szBuffer); //显示数字的文本框ID为27(即等于VK_ESCAPE) } DWORD CalcIt(UINT iFirstNum, int iOperation, UINT iNum) { switch (iOperation) { case ‘=‘:return iNum; case ‘+‘:return iFirstNum + iNum; case ‘-‘:return iFirstNum - iNum; case ‘*‘:return iFirstNum * iNum; case ‘/‘:return iNum ? iFirstNum / iNum : MAXDWORD; case ‘&‘:return iFirstNum & iNum; case ‘|‘:return iFirstNum | iNum; case ‘^‘:return iFirstNum ^ iNum; case ‘>‘:return iFirstNum >> iNum; case ‘<‘:return iFirstNum << iNum; case ‘%‘:return iNum ? iFirstNum%iNum : MAXDWORD; default:return 0; } } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL bNewNumber = TRUE; static int iOperation = ‘=‘; static UINT iNumber, iFirstNum; HWND hButton; switch (message) { case WM_KEYDOWN: //左方向键执行删除操作 if (wParam != VK_LEFT) break; wParam = VK_BACK; //继续执行下去 case WM_CHAR: //CharUpper的参数如果高位字为0,表示转换单个字符。否则表示一个字符串的指针,将转换字符串。 wParam = (WPARAM)CharUpper((TCHAR*)wParam); //转为大写字符 if (wParam == VK_RETURN) wParam = ‘=‘; //获得字符所对应的按钮 if (hButton = GetDlgItem(hwnd, wParam)) { SendMessage(hButton, BM_SETSTATE, 1, 0); //按下状态,高亮显示 Sleep(100); SendMessage(hButton, BM_SETSTATE, 0, 0); //释放状态 } else { MessageBeep(0); break; } //继续执行下去 case WM_COMMAND: //LOWORD(wParam)为控件ID,也是字符的ASCII码 SetFocus(hwnd); //每次单击按钮时,焦点总是设为父窗口。 //否则,焦点会停留在按钮上面,从而导致键盘消息失效 if (LOWORD(wParam) == VK_BACK) //退格键 ShowNumber(hwnd, iNumber /= 16); else if (LOWORD(wParam) == VK_ESCAPE) //取消键 ShowNumber(hwnd, iNumber = 0); else if (isxdigit(LOWORD(wParam))) //十六进制数 { if (bNewNumber) //新操作数的开始 { iFirstNum = iNumber; iNumber = 0; } bNewNumber = FALSE; if (iNumber <= MAXDWORD >> 4) //iNumber<=0x0FFFFFFF才可再输入一位,即iNumber最大值=0xFFFFFFFF { iNumber = 16 * iNumber + wParam - (isdigit(wParam) ? ‘0‘ : ‘A‘ - 10); //数字时wParam-‘0‘, //字母时(wParam-‘A‘)+10,即wParam-(‘A‘-10); ShowNumber(hwnd, iNumber); } else { MessageBeep(0); } } else //操作符 { if (!bNewNumber) //防止连续多次按操作符(如多次按加号),出现重复计算现象 { iNumber = CalcIt(iFirstNum, iOperation, iNumber); ShowNumber(hwnd, iNumber); } bNewNumber = TRUE; iOperation = LOWORD(wParam); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 HexCalc.rc 使用 // // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 #define _APS_NEXT_RESOURCE_VALUE 104 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1003 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//HexCalc.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Dialog // HEXCALC DIALOGEX 0, 0, 127, 184 STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU CAPTION "Hex Calculator" CLASS "HexCalc" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN PUSHBUTTON "0", 27, 15, 14, 89, 14 PUSHBUTTON "D", 68, 8, 41, 18, 18 PUSHBUTTON "E", 69, 30, 41, 18, 18 PUSHBUTTON "F", 70, 52, 41, 18, 18 PUSHBUTTON "A", 65, 8, 64, 18, 18 PUSHBUTTON "B", 66, 30, 64, 18, 18 PUSHBUTTON "C", 67, 52, 64, 18, 18 PUSHBUTTON "0", 48, 8, 156, 18, 18 PUSHBUTTON "1", 49, 8, 133, 18, 18 PUSHBUTTON "2", 50, 30, 133, 18, 18 PUSHBUTTON "3", 51, 52, 133, 18, 18 PUSHBUTTON "4", 52, 8, 110, 18, 18 PUSHBUTTON "5", 53, 30, 110, 18, 18 PUSHBUTTON "6", 54, 52, 110, 18, 18 PUSHBUTTON "7", 55, 8, 87, 18, 18 PUSHBUTTON "8", 56, 30, 87, 18, 18 PUSHBUTTON "9", 57, 52, 87, 18, 18 PUSHBUTTON "+", 43, 74, 41, 18, 18 PUSHBUTTON "-", 45, 74, 64, 18, 18 PUSHBUTTON "*", 42, 74, 87, 18, 18 PUSHBUTTON "/", 47, 74, 110, 18, 18 PUSHBUTTON "&&", 38, 96, 41, 18, 18 PUSHBUTTON "|", 124, 96, 64, 18, 18 PUSHBUTTON "^", 94, 96, 87, 18, 18 PUSHBUTTON "<", 60, 96, 110, 18, 18 PUSHBUTTON "%", 37, 74, 133, 18, 18 PUSHBUTTON ">", 62, 96, 133, 18, 18 PUSHBUTTON "Back", 8, 30, 156, 40, 18 PUSHBUTTON "Equals", 61, 74, 156, 40, 18 END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN "HEXCALC", DIALOG BEGIN RIGHTMARGIN, 124 BOTTOMMARGIN, 182 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. HEXCALC ICON "HexCalc.ico" #endif // 中文(简体,中国) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED