更复杂的对话框
ABOUT2.CPP
#include #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM) ; BOOL CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM); int iCurrentColor = IDC_BLACK; int iCurrentFigure = IDC_RECT; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, INT iCmdShow) { static TCHAR szAppName[] = TEXT ("About2") ; MSG msg; HWND hwnd; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon(hInstance, szAppName) ; wndclass.hCursor = LoadCursor(NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = szAppName ; wndclass.lpszClassName = szAppName ; if (!RegisterClass(&wndclass)) { MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } HMENU hMenu = LoadMenu(hInstance,MAKEINTRESOURCE(ABOUT2)); hwnd = CreateWindow(szAppName, TEXT ("About Box Demo Program"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, hMenu, hInstance, NULL ); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } void PaintWindow(HWND hwnd, int iColor, int iFigure) { static COLORREF crColor[8] = { RGB(0,0,0), RGB(0,0,255), RGB(0,255,0), RGB(0,255,255), RGB(255,0,0), RGB (255,0,255), RGB(255,255,0), RGB(255,255,255)} ; HBRUSH hBrush; HDC hdc; RECT rect; //PaintWindow函数取得一个设备内容句柄 //并将其放到hCtrl中 hdc = GetDC(hwnd); //子窗口控件的大小从GetClientRect获得 //GetClientRect取得以图素为单位的尺寸 GetClientRect(hwnd, &rect); //用函数MapDialogRect将对话框中的字符坐标转换为显示区域中的图素坐标 hBrush = CreateSolidBrush(crColor[iColor - IDC_BLACK]); //该函数选择一对象到指定的设备上下文环境中, //该新对象替换先前的相同类型的对象 hBrush = (HBRUSH)SelectObject(hdc, hBrush); //画出所选图形,根据所选 //颜色用一个着色画刷填入图形 if (iFigure == IDC_RECT) Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom); else Ellipse(hdc, rect.left, rect.top, rect.right, rect.bottom); //DeleteObject该函数删除一个逻辑笔、画笔、字体、位图、 //区域或者调色板,释放所有与该对象有关的系统资源, //在对象被删除之后,指定的句柄也就失效了。 DeleteObject(SelectObject(hdc, hBrush)); ReleaseDC(hwnd, hdc); } //这个函数使得子窗口控件无效 //并为控件窗口消息处理程序产生一个WM_PAINT消息 void PaintTheBlock(HWND hCtrl, int iColor, int iFigure) { //该函数向指定的窗体添加一个矩形 //然后窗口客户区域的这一部分将被重新绘制。 //第三个参数:TRUE时需要重画。 InvalidateRect(hCtrl, NULL, TRUE); //UpdateWindow函数通过发送一个WM_PAINT消息 //来更新指定窗口的客户区。 UpdateWindow(hCtrl); PaintWindow(hCtrl, iColor, iFigure); } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam) { static HINSTANCE hInstance; PAINTSTRUCT ps; switch (message) { case WM_CREATE: hInstance =((LPCREATESTRUCT)lParam)->hInstance; return 0; case WM_COMMAND: switch(LOWORD(wParam)) { case IDM_APP_ABOUT: //如果DialogBox传回TRUE(非0),则意味着按下了「OK」按钮 //这时对话框的状态可以应用到主窗口中了 if(DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), hwnd, AboutDlgProc)) InvalidateRect(hwnd, NULL, TRUE); return 0; } break; case WM_PAINT: BeginPaint(hwnd, &ps); EndPaint(hwnd, &ps); PaintWindow(hwnd, iCurrentColor, iCurrentFigure); return 0; case WM_DESTROY: //该函数向系统表明有个线程有终止请求 //用来响应WM_DESTROY消息。 PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hCtrlBlock; static int iColor, iFigure; switch (message) { case WM_INITDIALOG: iColor = iCurrentColor; iFigure = iCurrentFigure; //该函数给一组单选按钮中的一个指定按钮加上选中标志 //并且清除组中其他按钮的选中标志。 CheckRadioButton(hDlg, IDC_BLACK, IDC_WHITE, iColor); CheckRadioButton(hDlg, IDC_RECT, IDC_ELLIPSE, iFigure); //可以用对话框句柄和控件ID来取得一个对话框控件的窗口句柄 hCtrlBlock = GetDlgItem(hDlg, IDC_PAINT); SetFocus(GetDlgItem(hDlg, iColor)); return FALSE ; case WM_COMMAND: //消息的wParam的低字组被设为控件的ID, //wParam的高字组是一个通知码,lParam值是控件的窗口句柄。 switch (LOWORD(wParam)) { case IDOK: //子窗口向其父窗口发送一个WM_COMMAND消息 iCurrentColor = iColor; iCurrentFigure = iFigure; //第2个参数:指定从创建对话框函数返回到应用程序的值。 EndDialog(hDlg, TRUE); return TRUE; case IDCANCEL: EndDialog(hDlg, FALSE); return TRUE; case IDC_BLACK: case IDC_RED: case IDC_GREEN: case IDC_YELLOW: case IDC_BLUE: case IDC_MAGENTA: case IDC_CYAN: case IDC_WHITE: iColor = LOWORD(wParam); CheckRadioButton(hDlg, IDC_BLACK, IDC_WHITE, iColor); PaintTheBlock(hCtrlBlock, iColor, iFigure); return TRUE; case IDC_RECT: case IDC_ELLIPSE: iFigure = LOWORD(wParam) ; CheckRadioButton(hDlg, IDC_RECT, IDC_ELLIPSE, LOWORD(wParam)); PaintTheBlock(hCtrlBlock, iColor, iFigure); return TRUE; } break; case WM_PAINT: PaintTheBlock(hCtrlBlock, iColor, iFigure); break; } return FALSE; }
资源文件
///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_DIALOG1 DIALOG 32, 32, 200, 234 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION FONT 8, "MS Sans Serif" BEGIN ICON "ABOUT2",IDC_STATIC,7,7,20,20 CTEXT "About2",IDC_STATIC,57,12,86,8 CTEXT "About Box Demo Program",IDC_STATIC,7,40,186,8 LTEXT "",IDC_PAINT,114,67,74,72 GROUPBOX "&Color",IDC_STATIC,7,60,84,143 RADIOBUTTON "&Black",IDC_BLACK,16,76,64,8,WS_GROUP | WS_TABSTOP RADIOBUTTON "B&lue",IDC_BLUE,16,92,64,8 RADIOBUTTON "&Green",IDC_GREEN,16,108,64,8 RADIOBUTTON "Cya&n",IDC_CYAN,16,124,64,8 RADIOBUTTON "&Red",IDC_RED,16,140,64,8 RADIOBUTTON "&Magenta",IDC_MAGENTA,16,156,64,8 RADIOBUTTON "&Yellow",IDC_YELLOW,16,172,64,8 RADIOBUTTON "&White",IDC_WHITE,16,188,64,8 GROUPBOX "&Figure",IDC_STATIC,109,156,84,46,WS_GROUP RADIOBUTTON "Rec&tangle",IDC_RECT,116,172,65,8,WS_GROUP | WS_TABSTOP RADIOBUTTON "&Ellipse",IDC_ELLIPSE,116,188,64,8 DEFPUSHBUTTON "OK",IDOK,35,212,50,14,WS_GROUP PUSHBUTTON "Cancel",IDCANCEL,113,212,50,14,WS_GROUP END
使用对话框控件
如上所示大多数子窗口控件发送WM_COMMAND消息给其父窗口(唯一例外的是滚动条控件)
如上RC文件中GROUPBOX控件是一个带标题(标题为「Color」或者「Figure」)的分组方块,每组单选按钮都由这样的分组方块包围。
选中和不选中按钮均需要向子窗口控件发送BM_CHECK消息。要设定一个按钮选中标记,您可以使用: SendMessage(hwndCtrl, BM_SETCHECK, 1, 0);
要消除选中标记,您可以使用: SendMessage (hwndCtrl, BM_SETCHECK, 0, 0);hwndCtrl参数是子窗口按钮控件的窗口句柄。
id = GetWindowLong (hwndCtrl, GWL_ID) ; //可以用对话框句柄和控件ID来取得一个对话框控件的窗口句柄
轮流使用所有八种颜色的ID值:
iColor = LOWORD(wParam); for(i = IDC_BLACK, i <= IDC_WHITE, i++) SendMessage(GetDlgItem (hDlg, i), BM_SETCHECK, i == LOWORD (wParam), 0); return TRUE;
第一种简化的方法是使用专门的对话框程序: SendDlgItemMessage (hDlg, id, iMsg, wParam, lParam) ;
第二种方法:CheckRadioButton (hDlg, idFirst, idLast, idCheck);这个函数将ID在idFirst到idLast之间的所有单选按钮的选中标记都清除掉.所以这个在使用复选框时,变得十分有用
如果是建立了一个「CHECKBOX」对话框窗口控件,那么可以使用如下的函数来设定和清除选中标记: CheckDlgButton (hDlg, idCheckbox, iCheck);如果iCheck设定为1,那么按钮被选中;如果设定为0,那么按钮不被选中。Check = IsDlgButtonChecked (hDlg, idCheckbox) ; //取得对话框中某个复选框的状态。
Tab停留和分组
Windows完成了将输入焦点从一个控件移动到另一个控件的所有工作。尽管如此,您必须在对话框模板中使用WS_TABSTOP和WS_GROUP窗口样式达到此目的。对于所有想要使用Tab键存取的控件,都要在其窗口样式中指定WS_TABSTOP。包含WS_TABSTOP样式的控件(特别是静态控件)不应该取得输入焦点,文字字段中的「&」将导致紧跟其后的字母以底线显示。
indows提供了两个函数,以便程序写作者找寻下一个或者前一个Tab键停留项或者组项
hwndCtrl = GetNextDlgTabItem (hDlg, hwndCtrl, bPrevious) ;
wndCtrl = GetNextDlgGroupItem (hDlg, hwndCtrl, bPrevious) ;
在对话框上画图
LTEXT "",IDC_PAINT,114,67,74,72 //使用位置和大小为我们想要画图的区域定义了一块空白文字控件
将其它函数用于对话框
EnableWindow(hwndCtrl, bEnable);
当bEnable为TRUE(非0)时,它启用控件;当bEnable为FALSE(0)时,它禁用控件。在控件被禁用时,它不再接收键盘或者鼠标输入。
定义自己的控件
#include #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK EllipPushWndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("About3") ; MSG msg; HWND hwnd; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = szAppName; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } //注册的窗口类别叫做「EllipPush」(椭圆形按键) wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = EllipPushWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = NULL; wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = TEXT("EllipPush"); RegisterClass(&wndclass); HMENU hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1)); hwnd = CreateWindow(szAppName, TEXT("About Box Demo Program"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, hMenu, hInstance, NULL); ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HINSTANCE hInstance; switch (message) { case WM_CREATE: hInstance = ((LPCREATESTRUCT) lParam)->hInstance; return 0; case WM_COMMAND: switch(LOWORD(wParam)) { case IDM_APP_ABOUT: DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), hwnd, AboutDlgProc); return 0; } break; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: EndDialog(hDlg, 0); return TRUE; } break; } return FALSE; } LRESULT CALLBACK EllipPushWndProc(HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam) { TCHAR szText[40]; HBRUSH hBrush; HDC hdc; PAINTSTRUCT ps; RECT rect; switch (message) { case WM_PAINT: //从GetClientRect中取得窗口的大小 GetClientRect(hwnd, &rect); //从GetWindowText中取得显示在按键上的文字 GetWindowText(hwnd, szText, sizeof(szText)); hdc = BeginPaint(hwnd, &ps) ; hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); hBrush = (HBRUSH)SelectObject(hdc, hBrush); SetBkColor(hdc, GetSysColor(COLOR_WINDOW)); SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); //用Windows函数Ellipse和DrawText来输出椭圆和文字 Ellipse(hdc, rect.left, rect.top, rect.right, rect.bottom); DrawText(hdc, szText, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); DeleteObject(SelectObject(hdc, hBrush)); EndPaint(hwnd, &ps); return 0; case WM_KEYUP: if (wParam != VK_SPACE) break ;// fall through case WM_LBUTTONUP: //GetParent来取得其父窗口(即对话框)的句柄 //并发送一个WM_COMMAND消息,消息的wParam等于控件的ID //这个ID是用GetWindowLong取得的。 //GWL_ID= (-12) 对话框中一个子窗口的标识符 SendMessage(GetParent(hwnd), WM_COMMAND, GetWindowLong(hwnd, GWL_ID), (LPARAM)hwnd); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
EllipPushWndProc只是一个空架子。例如,按钮不会像普通的按键那样闪烁。要翻转按键内的颜色,窗口消息处理程序必须处理WM_KEYDOWN(来自空格键)和WM_LBUTTONDOWN消息。EllipPushWndProc也不处理WM_ENABLE消息。如上所述,对话框程序可以使用EnableWindow函数来禁用某窗口。