在笔者上篇博文《Delphi MessageBox消息框应用窗口居中实用解决方案》中,提到了用新线程操作 MessageBox 消息对话框,使其显示在 HWND 窗口中央而不是桌面中央。其实,在新线程中还可以对消息框做更多的操作。本文就增加一个定时回答默认按钮的功能,可在一定时间后自动选择默认选项,关闭消息对话框,从而让程序自动进行下去。只增加几行代码和一个指定等待时间的全局变量就能实现这个功能。具体代码如下:

  • implementation

  • {$R *.dfm}

  • //===========从这里开始到下面结束这段代码放在调用程序之前即可================
  • type
  •  TMyThread = class(TThread)        //定义新线程
  •  protected
  •    procedure Execute; override;      //新线程创建后即运行
  •  end;
  • var
  •  hMain: HWND;                
  •  MsgTitle: string;
  •  WaitColse: integer;        //全局变量,通过它们向新线程传递相关参数

  • procedure TMyThread.Execute; //新线程执行程序
  • var
  •  mR, pR, sR: TRect;
  •  k, X, Y: Integer;
  •  hMsg: HWND;
  • begin
  •  FreeOnTerminate := True; { 这可以让线程执行完毕后随即释放 }
  •  sleep(5); // 等消息框建立
  •  hMsg := FindWindow(nil, PChar(MsgTitle)); //根据消息窗口标题获取其句柄

  •  GetWindowRect(hMsg, mR); // 取消息框窗口矩形位置大小
  •  GetWindowRect(hMain, pR); // 取父窗口矩形位置大小
  •  GetWindowRect(GetDesktopWindow, sR); // 取屏幕桌面矩形位置大小

  •  X := pR.Left + (pR.Width - mR.Width) div 2;
  •  Y := pR.Top + (pR.Height - mR.Height) div 2; //将消息框座标设定在HWND窗口中央

  •  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); //将消息框移动到 HWND 窗口中央。
  •  if WaitColse = 0 then  //如果等待时间为0,则与原来一样,等待用户响应
  •    exit;
  •  k := 0;
  •  while k < WaitColse do
  •  begin
  •    sleep(1000);
  •    inc(k);
  •  end;             //等待WaitColse秒。
  •  PostMessage(hMsg, WM_KEYDOWN, 13, 0);
  •  PostMessage(hMsg, WM_KEYUP, 13, 0);        //向消息框窗口发送回车,选择默认按钮
  • end;

  • // 主函数。在HWND中央显示消息框。Wait为等待时间(秒),为0或省略则一直等待用户选择。
  • function MsgBox(const HWND: HWND; const msg, title: string;
  •  const mbType: WORD; const Wait: integer = 0): WORD;
  • begin
  •  hMain := HWND;
  •  if not IsWindow(hMain) then
  •    hMain := GetDesktopWindow;  //如果HWND不存在则为桌面
  •  if title <> '' then
  •    MsgTitle := title
  •  else
  •    MsgTitle := #32;                //如果消息对话框无标题则将标题设为空格方便新线程查找
  •  WaitColse := Wait;              
  •  TMyThread.Create(False); //创建新线程且立即运行
  •  result := MessageBox(HWND, PChar(msg), PChar(MsgTitle), mbType + MB_TOPMOST);
  • end;
  • // ==========================代码结束=============================

  扩展后的函数为 MsgBox,如果HWND = 0且省略 Wait 参数,则与 MessageBox 完全一样。

  扩展用法:

  如果 HWND 存在,MessageBox 窗口将显示在该窗口的中央,否则显示在桌面中央;

  如果有 Wait 参数且不为0,则用户如果在 Wait 秒内没有选择按钮,到时自动选择默认按钮。

例如:

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

  按  Form3 中的 Button1 按钮后,消息框会显示在 Form3 窗口中央。在5秒内用户如果按Yes,则关闭 Form3,如果5秒后还未操作,则自动按默认选项 No,关闭消息对话框。