【问题标题】:C++: How to center MessageBox?C++:如何将 MessageBox 居中?
【发布时间】:2011-06-09 21:56:02
【问题描述】:

将 Visual Studio C++ 与 MFC 结合使用。如何将 MessageBox 居中到它的父窗口?目前它以桌面为中心。

【问题讨论】:

  • 在 MessageBox 调用之前使用 PostMessage()。在您的消息处理程序中,使用 EnumWindows 找到消息框,然后将 MoveWindow 移到您想要的位置。
  • 消息框的类 #32770 应该可以帮助您找到它
  • 有一种方法可以改变位置,但是对于这么小的任务来说它太复杂了。只需创建您自己的 CDialog。

标签: c++ windows mfc center messagebox


【解决方案1】:

::AfxMessageBox() 对我来说出现在 MainFrame 的中心。这基本上是对 ::MessageBox() 的调用,其中 MainFrame 的句柄作为第一个参数。这不适合你吗?

【讨论】:

  • 对我不起作用。它可能以应用程序的“MainFrame”为中心,但我需要它以我的 CDialog 派生对话框为中心(我从中调用 MessageBox/AfxMessageBox)。
【解决方案2】:

您需要安装一个钩子并在创建时更改对话框位置。

int MessageBoxCentered(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
    // Center message box at its parent window
    static HHOOK hHookCBT{};
    hHookCBT = SetWindowsHookEx(WH_CBT,
        [](int nCode, WPARAM wParam, LPARAM lParam) -> LRESULT
        {
            if (nCode == HCBT_CREATEWND)
            {
                if (((LPCBT_CREATEWND)lParam)->lpcs->lpszClass == (LPWSTR)(ATOM)32770)  // #32770 = dialog box class
                {
                    RECT rcParent{};
                    GetWindowRect(((LPCBT_CREATEWND)lParam)->lpcs->hwndParent, &rcParent);
                    ((LPCBT_CREATEWND)lParam)->lpcs->x = rcParent.left + ((rcParent.right - rcParent.left) - ((LPCBT_CREATEWND)lParam)->lpcs->cx) / 2;
                    ((LPCBT_CREATEWND)lParam)->lpcs->y = rcParent.top + ((rcParent.bottom - rcParent.top) - ((LPCBT_CREATEWND)lParam)->lpcs->cy) / 2;
                }
            }

            return CallNextHookEx(hHookCBT, nCode, wParam, lParam);
        },
        0, GetCurrentThreadId());

    int iRet{ MessageBox(hWnd, lpText, lpCaption, uType) };

    UnhookWindowsHookEx(hHookCBT);

    return iRet;
}

【讨论】:

    【解决方案3】:

    你不能。这就是为什么很多人编写自己的 MessageBox 类的原因。

    【讨论】:

      【解决方案4】:

      谁说“不能”?

      试试这个:

      这是用于 Win32 API,用 C 编写的。根据需要翻译它...

      case WM_NOTIFY:{
        HWND X=FindWindow("#32770",NULL);
        if(GetParent(X)==H_frame){int Px,Py,Sx,Sy; RECT R1,R2;
          GetWindowRect(hwnd,&R1); GetWindowRect(X,&R2);
          Sx=R2.right-R2.left,Px=R1.left+(R1.right-R1.left)/2-Sx/2;
          Sy=R2.bottom-R2.top,Py=R1.top+(R1.bottom-R1.top)/2-Sy/2;
          MoveWindow(X,Px,Py,Sx,Sy,1);
        }
      } break;
      

      将它添加到 WndProc 代码...您可以根据需要设置位置,在这种情况下,它只是位于主程序窗口的中心。它将对任何消息框或文件打开/保存对话框以及可能的其他一些本机控件执行此操作。我不确定,但我认为您可能需要包含 COMMCTRL 或 COMMDLG 才能使用它,至少,如果您想要打开/保存对话框,您会这样做。

      我尝试查看 NMHDR 的通知代码和 hwndFrom,然后认为它同样有效,而且更容易,而不是。如果您真的想要非常具体,请告诉 FindWindow 查找您为希望它找到的窗口提供的唯一标题(标题)。

      这会在消息框绘制到屏幕上之前触发,因此如果您设置一个全局标志来指示您的代码何时执行操作,并寻找一个唯一的标题,您可以确保您执行的操作只会发生一次(将会可能是多个通知者)。我没有对此进行详细探讨,但我设法让 CreateWindow 在消息框对话框上放置一个编辑框。它看起来就像将老鼠的耳朵移植到克隆猪的脊椎上一样不合适,但它确实有效。以这种方式做事可能比自己动手要容易得多。

      乌鸦。

      编辑:处理 Raymond Chen 提出的问题的小修正。确保父句柄始终一致,这应该可以正常工作。它对我有用,即使是同一个程序的两个实例......

      【讨论】:

      • 请注意,这会找到 a 消息框,不一定是 your 消息框。
      • 没问题... 将if(X) 替换为if(GetParent(X)==H_frame) 并且程序中的文件对话框和消息框也由 H_frame 或任何句柄名称作为父级,其值将是唯一的,因此甚至是多个同一程序的实例将安全共存。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多