///////////////////////////////////////////////////////////////////////// //《Windows程序设计》第11章对话框代码ABOUT2 ///////////////////////////////////////////////////////////////////////// #include <Windows.h> #include "RESOURCE.H" LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); BOOL CALLBACK AboutDlgProc(HWND,UINT,WPARAM,LPARAM); int iCurrentColor=IDC_BLACK,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_VREDRAW|CS_HREDRAW; 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.lpszClassName=szAppName; wndclass.lpszMenuName=szAppName; if(!RegisterClass(&wndclass)) { MessageBox(NULL,TEXT("This program requires Windows NT!"),szAppName,MB_ICONERROR); return 0; } hwnd=CreateWindow(szAppName,TEXT("About Box Demo Program"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,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; hdc=GetDC(hwnd); GetClientRect(hwnd,&rect); 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(SelectObject(hdc,hBrush)); ReleaseDC(hwnd,hdc); } //对下面这个函数不理解,常规想法应该是PaintWindow后再UpdateWindow,但事实这样不可以,系统会卡住 void PaintTheBlock(HWND hCtrl,int iColor,int iFigure) { //使子窗口控件无效 InvalidateRect(hCtrl,NULL,TRUE); //如果窗口更新的区域不为空,UpdateWindow函数通过发送一个WM_PAINT消息来更新指定窗口的客户区。 //函数绕过应用程序的消息队列,直接发送WM_PAINT消息给指定窗口的窗口过程,如果更新区域为空,则不发送消息。 //对此UpdateWindow还不是不懂 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: //根据对话框模板资源创建一个模态的对话框 //这边是回调完成后才触发的 //直到指定的回调函数通过调用EndDialog函数中止模态的对话框才能返回控制。 //调用失败,返回-1 //调用成功,返回EndDialog中的参数 if(DialogBox(hInstance,TEXT("AboutBox"),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: 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); //获取设置面板中展示区控件的句柄 hCtrlBlock=GetDlgItem(hDlg,IDC_PAINT); //设置焦点 SetFocus(GetDlgItem(hDlg,iColor)); //这个返回TRUE跟FALSE,好像对结果没啥影响,不知其原因 return FALSE; case WM_COMMAND: //LOWORD(wParam)是指明哪个控件 switch(LOWORD(wParam)) { case IDOK: iCurrentColor=iColor; iCurrentFigure=iFigure; //这个返回关系着DialogBox的返回 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,LOWORD(wParam)); //小窗口区的时时更新 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; } ///////////////////////////////////////////////////////////////////////// //在一开始生成子窗口时,调用过程如下: //PaintTheBlock----------->UpdateWindow-------->PaintWindow //在切换颜色与形状时,调用过程如下: //UpdateWindow--------->PaintWindow //UpdateWindow到底做了什么?不是说会调用WM_PAINT么,但是我设置断点却没有 /////////////////////////////////////////////////////////////////////////
看了几个帖子,好像大体理解了这个问题。
1、PaintTheBlock中传入的第一个参数并不是子窗口的,而是子窗口中一个Text控件的(用来画图的)。
2、调用InvalidateRect是来设置这个子窗口控件的区域无效
3、调用UpdateWindow是用来触发WM_PAINT,这个WM_PAINT是这个子窗口控件的WM_PAINT,而不是子窗口的。
4、上面两句代码的意思应该就是想清除这个文本控件的特征吧,然后直接来画图。
不知道这么理解对不对,还希望各位多多提意见