0

我有一个启动时全屏运行的 win32 应用程序。该应用程序有一些按钮可以调用弹出对话框。

有没有办法让整个桌面(除了弹出窗口)变成透明的黑色,除非弹出窗口被用户关闭?我所说的类似于 Windows 7 UAC 弹出窗口及其导致的背景。

是否可以为全屏窗口应用程序做类似的事情?

4

1 回答 1

2

有可能这样做……有点。也许我应该说,你可以模拟这种效果。它实际上不会像 UAC 对话框那样,因为用户仍然能够与其他正在运行的应用程序进行交互。应用程序没有“系统模式”这样的概念。当然,这是设计使然。但是您当然可以显示一个“灯箱”,使桌面的其余部分变暗并强制将注意力集中在应用程序的对话框上。

我这样做的方法是创建一个巨大的分层窗口,它位于所有其他窗口的顶部并覆盖整个屏幕,用黑色填充它,并根据需要设置不透明度。然后,在显示模式对话框之前(通过调用 MessageBox 函数或使用 DialogBox 函数显示您自己的自定义对话框之一),显示您的灯箱窗口。最后,在用户关闭模态对话框后,您将销毁灯箱窗口。

这是一些示例代码。为简洁起见,省略了错误检查。其他好的风格也是如此,例如将这种混乱包装在一个或多个类中。

INT_PTR ShowLightBoxedDialog(HINSTANCE hInstance,
                             LPCTSTR pDlgTemplate,
                             HWND hwndParent,
                             DLGPROC pDlgProc,
                             BYTE opacityLevel)
{
   const TCHAR szLightBoxClass[] = TEXT("LightBoxWndClass");

   // Register the light box window class.
   static bool lightBoxRegistered = false;
   if (!lightBoxRegistered)
   {
      WNDCLASSEX wcex;
      wcex.cbSize          = sizeof(wcex);
      wcex.style           = CS_NOCLOSE | CS_SAVEBITS;
      wcex.lpfnWndProc     = LightBoxWndProc;
      wcex.cbClsExtra      = 0;
      wcex.cbWndExtra      = 0;
      wcex.hInstance       = hInstance;
      wcex.hIcon           = NULL;
      wcex.hIconSm         = NULL;
      wcex.hCursor         = LoadCursor(NULL, IDC_ARROW);
      wcex.hbrBackground   = NULL;
      wcex.lpszMenuName    = NULL;
      wcex.lpszClassName   = szLightBoxClass;
      RegisterClassEx(&wcex);
      lightBoxRegistered = true;
   }

   // Create and display the light box window.
   HWND hwndLightBox = CreateWindowEx(WS_EX_NOACTIVATE | WS_EX_LAYERED,
                                      szLightBoxClass,
                                      NULL,
                                      WS_POPUPWINDOW,
                                      0, 0, 0, 0,
                                      hwndParent,
                                      NULL,
                                      hInstance,
                                      NULL);
   SetLayeredWindowAttributes(hwndLightBox, 0, opacityLevel, LWA_ALPHA);
   SetWindowPos(hwndLightBox,
                HWND_TOP,
                GetSystemMetrics(SM_XVIRTUALSCREEN),
                GetSystemMetrics(SM_YVIRTUALSCREEN),
                GetSystemMetrics(SM_CXVIRTUALSCREEN),
                GetSystemMetrics(SM_CYVIRTUALSCREEN),
                SWP_SHOWWINDOW);

   // Display the modal dialog box (as you normally would).
   // NOTE: The dialog box won't appear centered on the screen.
   // For that, you will need to write centering code in response
   // to the WM_INITDIALOG message in the dialog procedure.
   INT_PTR result = DialogBox(hInstance, pDlgTemplate, hwndLightBox, pDlgProc);
   // 
   // For demonstration purposes, I used the following code:
   // INT_PTR result = MessageBox(hwndLightBox,
   //                             TEXT("OH NOEZ!\n\nYour system is kaput! Abandon þe all hope."),
   //                             NULL,
   //                             MB_ABORTRETRYIGNORE | MB_ICONERROR);

   // Destroy the light box window.
   DestroyWindow(hwndLightBox);

   // Return the result of the modal dialog box.
   return result;
}

您会注意到,基本上我所做的是围绕DialogBox 函数创建了一个包装器,只要您想要一个具有“灯箱”效果的对话框,就可以使用它。它采用所有相同的参数(前 4 个),然后在末尾添加一个额外的参数,允许您指定用于“灯箱”效果的不透明度级别。150-200 范围内的东西可能是好的。当然,您可以选择一些东西并对其进行硬编码,但我对硬编码值严重过敏。无论如何,从任何地方调用这个函数都非常容易:

ShowLightBoxedDialog(hInstance,                   /* your application instance */
                     MAKEINTRESOURCE(IDD_SAMPLE), /* your dialog template      */
                     hWnd,                        /* parent window for dialog  */
                     SampleWndProc,               /* ptr to dialog procedure   */
                     175);                        /* light box opacity level   */

因为代码利用了 Windows 中模式对话框的工作原理,所以用户在关闭对话框之前将无法与应用程序的任何其他部分进行交互。而且因为“灯箱”窗口位于其他所有内容之上,它会吃掉所有鼠标点击并阻止将焦点设置到任何其他应用程序。Alt但是使用+之类的东西是微不足道的Tab
所以这不是一个安全功能!这只是一种视觉效果!

而且因为它只是一种愚蠢的视觉效果,它可能会让你的用户感到沮丧。我实际上不建议使用它。但现在你知道该怎么做了。负责任地行使这种权力,等等。

于 2013-04-19T23:59:15.320 回答