为什么TApplication.MessageBox自动关闭?

问题描述 投票:2回答:1

我有一个需要花费几秒钟来加载的应用程序(大量的初始化)。 GUI在启动期间冻结。因此,我想创建一个初始屏幕,该初始屏幕在应用程序加载时淡入和淡出。我使用TBackgroundWorker组件在后台线程中制作动画。

但是,当我使用此组件时,会发生一些奇怪的事情:当它表示“工作已完成”(请参阅​​BackgroundWorkerWorkComplete)时,我同时打开的消息对话框将自动关闭。

procedure TMainForm.ButtonStartSplashClick(Sender: TObject);
VAR
  frmSplash: TfrmSplash;
begin
 frmSplash:= TfrmSplash.Create(NIL);
 frmSplash.StartAnimation;

 //MessageBox(Handle, 'Hi', nil, MB_OK);   // This remains on screen
 Application.MessageBox(PChar('Hi'), PChar('Box'), MB_ICONINFORMATION); // This is automatically closed when the background thread is done
end;

这是启动画面:

procedure TfrmSplash.StartAnimation;
begin
 Show;
 BackgroundWorker.Execute;
end;


procedure TfrmSplash.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Action:= caFree;
end;


procedure TfrmSplash.BackgroundWorkerWork(Worker: TBackgroundWorker);
VAR i: Integer;
begin
  for i:= 1 to 255 DO
   begin
    AlphaBlendValue:= i; // do not access GUI directly from thread
    Sleep(30);
   end;
end;


procedure TfrmSplash.BackgroundWorkerWorkComplete(Worker: TBackgroundWorker; Cancelled: Boolean);
begin
 Close; // At this point, the msg box will be closed also
end;

我发现奇怪的是,MessageBox仍保留在屏幕上,而Application.MessageBox没有(自动关闭)。

为什么关闭TfrmSplash也将关闭消息框?

multithreading delphi backgroundworker splash-screen tform
1个回答
5
投票

TApplication.MessageBoxWinAPI MessageBox函数的包装。前者的代码向您展示了它的调用方式:

function TApplication.MessageBox(const Text, Caption: PChar; Flags: Longint): Integer;
var
  ActiveWindow, TaskActiveWindow: HWnd;
  MBMonitor, AppMonitor: HMonitor;
  MonInfo: TMonitorInfo;
  Rect: TRect;
  FocusState: TFocusState;
  WindowList: TTaskWindowList;
begin
  ActiveWindow := ActiveFormHandle;
  if ActiveWindow = 0 then
    TaskActiveWindow := Handle
  else
    TaskActiveWindow := ActiveWindow;

   {  ... }


  try
    Result := Winapi.Windows.MessageBox(TaskActiveWindow, Text, Caption, Flags);
  finally

注意,传递给WinAPI调用的HWND是TaskActiveWindow,它在进行调用时被视为活动窗口(除非没有,在这种情况下,将使用应用程序的句柄)。由于您刚刚创建了TFrmSplash,它将成为活动窗口,并且在关闭其父窗口(您的启动窗口)时将丢弃消息框。

当您直接直接调用MessageBox时:

 MessageBox(Handle, 'Hi', nil, MB_OK);   // This remains on screen

您正在传递Handle,这是您从中调用代码的表单的句柄,在本例中为TMainForm,因此在这种情况下,主表单成为所有者,并且与启动画面。

© www.soinside.com 2019 - 2024. All rights reserved.