无法使用 PropSheet 创建居中的属性表对话框

发布于 2024-12-20 03:42:19 字数 1862 浏览 1 评论 0原文

我正在使用以下设置创建一个无模式属性表:

   PROPSHEETHEADER pshdr = { 0 };

   pshdr.dwSize = sizeof(PROPSHEETHEADER);
   pshdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE |
                   PSH_MODELESS | PSH_USECALLBACK;
   pshdr.pfnCallback = PropSheetProc;
   pshdr.hwndParent = mGlobalState->trayWin;
   pshdr.pszCaption = L"My Settings";
   pshdr.nPages = mPages.size();
   pshdr.ppsp = mWinPages;

在 PropSheetProc 中,我捕获 PSCB_PRECREATE 消息并修改对话框模板,以便它获得 DS_CENTER 样式:

static int CALLBACK
PropSheetProc(HWND hwndDlg,  // IN
              UINT uMsg,     // IN
              LPARAM lParam) // IN
{
   // Before the dialog is created, bless it with the DS_CENTER style.
   if (uMsg == PSCB_PRECREATE) {
      DLGTEMPLATE *dlgTemplate = (DLGTEMPLATE *)lParam;
      _ASSERT(dlgTemplate);

      dlgTemplate->style |= DS_CENTER;
   }

   return 0;
}

但是,这无法成功使对话框居中。我尝试捕获 PSCB_INITIALIZED 并在传递给 PropSheetProc 的 hwnd 上调用 CenterWindow 方法:

void
CenterWindow(HWND hwndWindow) // IN
{
   int nX, nY, nScreenWidth, nScreenHeight;
   RECT rectWindow;

   nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
   nScreenHeight = GetSystemMetrics(SM_CYSCREEN);

   GetWindowRect(hwndWindow, &rectWindow);

   nX = (nScreenWidth - (rectWindow.right - rectWindow.left)) / 2;
   nY = (nScreenHeight - (rectWindow.bottom - rectWindow.top)) / 2;

   SetWindowPos(hwndWindow, 0, nX, nY, 0, 0,
                SWP_NOZORDER | SWP_NOSIZE);
}

但这也不起作用!

最后,我将 CenterWindow 调用直接移到 PropSheet 调用之后:

   mHwnd = (HWND)PropertySheet(&pshdr);
   CenterWindow(mHwnd);
   return mHwnd != NULL;

这确实有效,但在负载较重的系统上,对话框会从其初始位置闪烁到最终位置,这不是最理想的。

使用 PropSheetProc 修改 DLGTEMPLATE 结构似乎很直观。实际上,我可以应用其他窗口样式。但DS_CENTER似乎没有效果。那么我做错了什么?我可以用很多方法来解决这个问题,但它为什么会被破坏呢?

I am creating a modeless property sheet using the following settings:

   PROPSHEETHEADER pshdr = { 0 };

   pshdr.dwSize = sizeof(PROPSHEETHEADER);
   pshdr.dwFlags = PSH_NOAPPLYNOW | PSH_PROPSHEETPAGE |
                   PSH_MODELESS | PSH_USECALLBACK;
   pshdr.pfnCallback = PropSheetProc;
   pshdr.hwndParent = mGlobalState->trayWin;
   pshdr.pszCaption = L"My Settings";
   pshdr.nPages = mPages.size();
   pshdr.ppsp = mWinPages;

In PropSheetProc, I catch the PSCB_PRECREATE message and modify the dialog template so that it gets the DS_CENTER style:

static int CALLBACK
PropSheetProc(HWND hwndDlg,  // IN
              UINT uMsg,     // IN
              LPARAM lParam) // IN
{
   // Before the dialog is created, bless it with the DS_CENTER style.
   if (uMsg == PSCB_PRECREATE) {
      DLGTEMPLATE *dlgTemplate = (DLGTEMPLATE *)lParam;
      _ASSERT(dlgTemplate);

      dlgTemplate->style |= DS_CENTER;
   }

   return 0;
}

However this doesn't succeed in centering the dialog. I tried to catch PSCB_INITIALIZED instead and call a CenterWindow method on the hwnd passed to the PropSheetProc:

void
CenterWindow(HWND hwndWindow) // IN
{
   int nX, nY, nScreenWidth, nScreenHeight;
   RECT rectWindow;

   nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
   nScreenHeight = GetSystemMetrics(SM_CYSCREEN);

   GetWindowRect(hwndWindow, &rectWindow);

   nX = (nScreenWidth - (rectWindow.right - rectWindow.left)) / 2;
   nY = (nScreenHeight - (rectWindow.bottom - rectWindow.top)) / 2;

   SetWindowPos(hwndWindow, 0, nX, nY, 0, 0,
                SWP_NOZORDER | SWP_NOSIZE);
}

But that doesn't work either!

Finally, I moved the CenterWindow call to directly after the PropSheet call:

   mHwnd = (HWND)PropertySheet(&pshdr);
   CenterWindow(mHwnd);
   return mHwnd != NULL;

And this DOES work, though on a heavily loaded system, the dialog flashes from its initial position over to its final position, which is suboptimal.

Using the PropSheetProc to modify the DLGTEMPLATE structure seems intuitive. Actually, I can apply other window styles. But DS_CENTER seems to have no effect. So what am I doing wrong? There's many ways I can work around this brokennness but why is it broken in the first place?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

疯了 2024-12-27 03:42:19

重载 CPropertySheet 的 InitialUpdate(),并将 CenterWindow() 调用放在那里。这种情况发生在窗口绘制在屏幕上之前,但在创建之后,因此它的 hwnd 将有效。没有任何破损。必须创建该对话框才能具有有效的 HWND。或者,如果您使用资源编辑器,您可以将其属性设置为居中,它将获得相同的结果。为什么要重载属性表的 WinProc? MFC 使用消息映射的全部原因是为了消除接触 WinProc 的需要。

如果您在 SDK 样式应用程序中使用原始 win api ::

在属性表的 WinProc 中处理 WM_CREATE。 LPARAM 中的 LPCREATE 结构将包含来自 create 调用的有效 HWND。只需确保将正确的参数传递回 WndProcDefault(),否则窗口创建将失败。

Overload the InitialUpdate() of the CPropertySheet, and place the CenterWindow() call there. This happens before the window is drawn on the screen, but after it is created, so it's hwnd will be valid. There is nothing broken. The dialog has to be Created to have a valid HWND. Alternatively, if your working with the resource editor you can set it's property to centered, and it will achieve the same result. Why are you overloading the WinProc for the propertysheet? The whole reason MFC uses message maps was to eliminate the need to even touch WinProc's.

If your using raw win api in a SDK style application ::

Handle WM_CREATE in the WinProc of the property sheet. The LPCREATE struct in the LPARAM will contain a valid HWND from the create call. Just make sure you pass the proper parameters back to WndProcDefault() otherwise window creation will fail.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文