分享

[Win32SDK基本]模态窗口和多窗口

 just4peterpan 2018-09-29

什么是模态窗口呢,想必大家都知道模态对话框和非模态对话框吧,模态窗口和模态对话框类似。假设我们需要在按钮单击时创建一个新窗口,如果只是在按钮单击消息里CreateWindow(Ex)一个新窗口,那么这个窗口和之前的窗口是独立的,他们同时接受用户的响应。那么我们想在新窗口完成它的使命之前让之前的窗口拒绝接收响应,就要创建一个“模态窗口”

如何创建模态窗口呢,其实模态窗口和真正的窗口一样,只是创建之前将之前的窗口禁用掉,关闭之后恢复先前的窗口而已。

如果创建的第二个窗口还是使用原来的窗口类,他和之前的窗口就会公用同一个窗口回调函数,我们可以根据回调函数发回的窗口句柄判断是那一个窗口,当然,如果我们愿意,我们可以使用SetWindowLong(Ptr)修改窗口回调函数或者干脆重新注册一个窗口类。我喜欢再注册一个窗口类,因为这么做最简单,程序最美观,不至于一个回调函数特别不清晰。

那么我们就可以通过收到第二个窗口的WM_DESTROY消息时恢复第一个窗口,不过那样会使代码显得有点乱,因此,我们先写一个函数:

  1. void Modal(HWND last){
  2. MSG msg;
  3. while (GetMessage(&msg, NULL, 0, 0))
  4. {
  5. TranslateMessage(&msg);
  6. DispatchMessage(&msg);
  7. }
  8. EnableWindow(last, TRUE);
  9. SetForegroundWindow(last);
  10. }

这个函数是做什么的呢,很简单,他重新写了一个消息循环(可以把这个消息循环称为模态循环),函数调用之后,线程的消息都转移到这个消息循环里了,当收到WM_QUIT消息时只退出这个消息循环,还有一个WinMain上的消息循环顶着,退出后再恢复之前的窗口,这样,我们只需要创建完窗口调用一下这个函数就OK了。

还是以我的博客“[Win32SDK基本] 窗口详解(超详细)”(地址:http://blog.csdn.net/zuishikonghuan/article/details/46378475)为模板,进一步编写。

首先,重新写一个我们的回调函数:

  1. LRESULT CALLBACK WndProc2(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2. {
  3. switch (uMsg){
  4. case WM_DESTROY:
  5. PostQuitMessage(0);
  6. return 0;
  7. }
  8. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  9. }

这是第二个窗口的“回调函数”

再在注册窗口类下面再注册一个窗口类

  1. int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
  2. _In_opt_ HINSTANCE hPrevInstance,
  3. _In_ LPTSTR lpCmdLine,
  4. _In_ int nCmdShow)
  5. {
  6. //InitCommonControls();
  7. //这里是在构建窗口类结构
  8. wc.style = CS_HREDRAW | CS_VREDRAW;
  9. wc.lpfnWndProc = WndProc;//窗口回调函数指针
  10. wc.cbClsExtra = 0;
  11. wc.cbWndExtra = 0;
  12. wc.hInstance = hInstance;//实例句柄
  13. wc.hIcon = LoadIcon(hInstance, TEXT("ICON_1"));
  14. wc.hCursor = LoadCursor(NULL, IDC_ARROW);//默认指针
  15. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);//默认背景颜色
  16. wc.lpszMenuName = NULL;
  17. wc.lpszClassName = AppName;//窗口类名
  18. //注册窗口类
  19. if (!RegisterClass(&wc))
  20. {
  21. MessageBox(NULL, TEXT("注册窗口类失败!"), TEXT("错误"), MB_ICONERROR);
  22. return 0;
  23. }
  24. //注册第二个窗口的窗口类
  25. wc.lpfnWndProc = WndProc2;
  26. wc.lpszClassName = AppName2;
  27. if (!RegisterClass(&wc))
  28. {
  29. MessageBox(NULL, TEXT("注册窗口类失败!"), TEXT("错误"), MB_ICONERROR);
  30. return 0;
  31. }//。。。。。。

创建模态窗口,在之前创建的又有文字又有图片的按钮的单击消息里创建:

  1. case WM_COMMAND:
  2. int id;
  3. int ent;
  4. ent = HIWORD(wParam);//通知吗
  5. id = LOWORD(wParam);//子窗口ID
  6. 。。。
  7. //判断按钮的单机事件
  8. if (ent == BN_CLICKED){
  9. switch (id)
  10. {
  11. case 4://按钮的子窗口ID
  12. 。。。
  13. case 7:
  14. EnableWindow(hwnd, FALSE);
  15. hwnd2 = CreateWindowEx(NULL, AppName2, TEXT("窗口标题"), WS_OVERLAPPEDWINDOW, 150, 150, 500, 500, hwnd,NULL, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), 0);
  16. if (hwnd2 == NULL)
  17. {
  18. MessageBox(NULL, TEXT("创建窗口失败!"), TEXT("错误"), MB_ICONERROR);
  19. return 0;
  20. }
  21. SetWindowLong(hwnd2, GWL_WNDPROC, (LONG)&WndProc2);
  22. ShowWindow(hwnd2, 5);
  23. UpdateWindow(hwnd2);
  24. Modal(hwnd);
  25. case 8://Check Boxes被单机
  26. 。。。。
  27. }
  28. }
  29. break;
注意CreateWindowEx的倒数第四个参数用之前的窗口的句柄。(父窗口,单和原来的窗口是两个窗口,如果这里不用hwnd,结果也能实现类似效果,但是单机之前的窗口时新窗口就不闪动了)

效果图:

(在第二个窗口关闭之前,第一个不能与用户交互)

多窗口:

创建一个新窗口与原来的窗口相互独立:

基本上一样,需要改两点:

1.去掉 EnableWindow(hwnd, FALSE); 和 Modal(hwnd);

2.将 CreateWindowEx  倒数第四个参数(父窗口)改为NULL

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多