Delphi MessageBox消息框应用窗口居中实用解决方案

  众所周知,Delphi 的 MessageBox 消息框是封装的 Win32 函数。其函数原型为:

​MessageBox(​​​​HWND​​ ​​hWnd,​​​​LPCTSTR​​ ​​lpText,​​​​LPCTSTR​​ ​​lpCaption,​​​​UINT​​ ​​uType);​

  其中各参数想必大家都很熟悉,在此不再赘述。主要谈谈 ​​HWND​​。按官方描述:此参数代表消息框拥有的窗口。如果为NULL,则​消息框​没有拥有窗口。按理说消息框就应该显示在 HWND 窗口中,但直至 Windows 11,无论 HWND 如何,消息框都稳占桌面中央。对于应用程序而言,我们希望这个消息框能显示在应用程序的主窗口正中,甚至派生窗口的正中。也就是说真正显示在 HWND 窗口正中。

  这个问题,网上已有人给出过解决方案。但有的只给出解决思路,有的虽然给出了解决方案,但用了Delphi最新版本才有的功能(如TThread.ForceQueue)。因此,我用最基本的Delphi方法给出一个实用的解决方案。作为实用的方案,考虑到了 MessageBox 不能移出屏幕边界、HNWD 窗口不存在即显示在桌面中央等实际情况。

  解决的原理很简单,就是想法将 MessageBox 移动到指定的位置。但 Windows 系统的 MessageBox 是一个模态对话框,也就是说直至用户响应才执行下一条程序指令,移动窗口的指令不可能在同一线程,必须开启另一个线程。这个线程在 MessageBox 弹出前建立且运行,等待 MessageBox 弹出后通过查找其窗口标题对应的窗口句柄(我的实验是不能通过顶层窗口或活动窗口查找 MessageBox),将其移动到指定位置后结束线程。这样就实现了将 MessageBox 显示在 HWND 窗口中央。具体程序如下,这段程序可放在 implementation 后的任何地方,只要在调用它的程序前就行:

  • implementation
    
    {$R *.dfm}
    
    type
     TMyThread = class(TThread)
     protected
       procedure Execute; override;
     end;
    
    var
     hMain: HWND;
     MsgTitle: string;
    
    procedure TMyThread.Execute;
    var
     mR, pR, sR: TRect;
     X, Y: Integer;
     hMsg: HWND;
    begin
     FreeOnTerminate := True;                  // 这可以让线程执行完毕后随即释放 
     sleep(5);                                 // 等消息框建立
     hMsg := FindWindow(nil, PChar(MsgTitle));
    
     GetWindowRect(hMsg, mR);                  // 取消息框窗口矩形位置大小
     GetWindowRect(hMain, pR);                 // 取 HWND 窗口矩形位置大小
     GetWindowRect(GetDesktopWindow, sR);      // 取屏幕桌面矩形位置大小
    
     X := pR.Left + (pR.Width - mR.Width) div 2;
     Y := pR.Top + (pR.Height - mR.Height) div 2;
     if X < 0 then
       X := 0;
     if X > sR.Width - mR.Width then
       X := sR.Width - mR.Width;
     if Y < 0 then
       Y := 0;
     if Y > sR.Height - mR.Height then
       Y := sR.Height - mR.Height;
    
     SetWindowPos(hMsg, HWND_TOP, X, Y, 0, 0, SWP_NOSIZE or SWP_SHOWWINDOW or
       SWP_NOOWNERZORDER);
    end;
    
    // 主函数。在HWND中央显示消息框
    function MsgBox(const HWND: HWND; const msg, title: string;
     const mbType: WORD): WORD;
    begin
     hMain := HWND;
     if not IsWindow(hMain) then
       hMain := GetDesktopWindow;
     if title <> '' then
       MsgTitle := title
     else
       MsgTitle := #32;
     TMyThread.Create(False);
     result := MessageBox(HWND, PChar(msg), PChar(MsgTitle), mbType + MB_TOPMOST);
    end;

   新的消息函数名为 MsgBox ,调用它与 MessageBox 完全相同。例如:

  • procedure TForm3.Button1Click(Sender: TObject);
    begin
      if  MsgBox(handle, '消息内容', '消息标题', MB_YESNO) = mrYes then
        close;
    end;

   运行后,MessageBox 显示在 Form3 窗口的中央而不是桌面中央(要显示桌面在中央,HWND指定为0即可)。按“是(Y)”将关闭 Form3:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值