什么是模态窗口呢,想必大家都知道模态对话框和非模态对话框吧,模态窗口和模态对话框类似。假设我们需要在按钮单击时创建一个新窗口,如果只是在按钮单击消息里CreateWindow(Ex)一个新窗口,那么这个窗口和之前的窗口是独立的,他们同时接受用户的响应。那么我们想在新窗口完成它的使命之前让之前的窗口拒绝接收响应,就要创建一个“模态窗口”
如何创建模态窗口呢,其实模态窗口和真正的窗口一样,只是创建之前将之前的窗口禁用掉,关闭之后恢复先前的窗口而已。
如果创建的第二个窗口还是使用原来的窗口类,他和之前的窗口就会公用同一个窗口回调函数,我们可以根据回调函数发回的窗口句柄判断是那一个窗口,当然,如果我们愿意,我们可以使用SetWindowLong(Ptr)修改窗口回调函数或者干脆重新注册一个窗口类。我喜欢再注册一个窗口类,因为这么做最简单,程序最美观,不至于一个回调函数特别不清晰。
那么我们就可以通过收到第二个窗口的WM_DESTROY消息时恢复第一个窗口,不过那样会使代码显得有点乱,因此,我们先写一个函数:
void Modal(HWND last){ MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } EnableWindow(last, TRUE); SetForegroundWindow(last); }
还是以我的博客“[Win32SDK基本] 窗口详解(超详细)”(地址:http://blog.csdn.net/zuishikonghuan/article/details/46378475)为模板,进一步编写。
首先,重新写一个我们的回调函数:
LRESULT CALLBACK WndProc2(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg){ case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); }
这是第二个窗口的“回调函数”
再在注册窗口类下面再注册一个窗口类
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) { //InitCommonControls(); //这里是在构建窗口类结构 wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc;//窗口回调函数指针 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance;//实例句柄 wc.hIcon = LoadIcon(hInstance, TEXT("ICON_1")); wc.hCursor = LoadCursor(NULL, IDC_ARROW);//默认指针 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);//默认背景颜色 wc.lpszMenuName = NULL; wc.lpszClassName = AppName;//窗口类名 //注册窗口类 if (!RegisterClass(&wc)) { MessageBox(NULL, TEXT("注册窗口类失败!"), TEXT("错误"), MB_ICONERROR); return 0; } //注册第二个窗口的窗口类 wc.lpfnWndProc = WndProc2; wc.lpszClassName = AppName2; if (!RegisterClass(&wc)) { MessageBox(NULL, TEXT("注册窗口类失败!"), TEXT("错误"), MB_ICONERROR); return 0; }//。。。。。。
创建模态窗口,在之前创建的又有文字又有图片的按钮的单击消息里创建:
case WM_COMMAND: int id; int ent; ent = HIWORD(wParam);//通知吗 id = LOWORD(wParam);//子窗口ID 。。。 //判断按钮的单机事件 if (ent == BN_CLICKED){ switch (id) { case 4://按钮的子窗口ID 。。。 case 7: EnableWindow(hwnd, FALSE); hwnd2 = CreateWindowEx(NULL, AppName2, TEXT("窗口标题"), WS_OVERLAPPEDWINDOW, 150, 150, 500, 500, hwnd,NULL, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), 0); if (hwnd2 == NULL) { MessageBox(NULL, TEXT("创建窗口失败!"), TEXT("错误"), MB_ICONERROR); return 0; } SetWindowLong(hwnd2, GWL_WNDPROC, (LONG)&WndProc2); ShowWindow(hwnd2, 5); UpdateWindow(hwnd2); Modal(hwnd); case 8://Check Boxes被单机 。。。。 } } break;注意CreateWindowEx的倒数第四个参数用之前的窗口的句柄。(父窗口,单和原来的窗口是两个窗口,如果这里不用hwnd,结果也能实现类似效果,但是单机之前的窗口时新窗口就不闪动了)
效果图:
(在第二个窗口关闭之前,第一个不能与用户交互)
多窗口:
创建一个新窗口与原来的窗口相互独立:
基本上一样,需要改两点:
1.去掉 EnableWindow(hwnd, FALSE); 和 Modal(hwnd);
2.将 CreateWindowEx 倒数第四个参数(父窗口)改为NULL