Windows任务栏关闭最小化FMX窗体时程序锁死问题求助
问题描述
我开发的FMX程序实现了关闭前确认逻辑:用户尝试关闭窗体时,程序会弹出模态对话框询问是否确认关闭。但存在以下异常:
- 窗体未最小化时,流程正常,对话框正常显示,用户可选择是否关闭
- 窗体最小化后从任务栏点击关闭按钮,程序直接锁死,只能通过任务管理器结束进程
- 排查发现模态确认对话框已创建但不可见,用户无法操作,即使恢复窗体也无法正常关闭程序
已知对比情况:
- 使用
TApplication.MessageBox的VCL程序无此问题,任务栏关闭时消息框正常弹出 - Delphi 10开发的同类FMX程序也无此问题
已尝试无效方案:
- 在显示消息框前强制将窗体
WindowState设为wsNormal并调用Application.ProcessMessages
需求:必须使用同步消息框,需等待用户点击"Yes"后才能关闭程序,防止未保存工作丢失。
相关代码
DFM文件
object Form1: TForm1 Left = 0 Top = 0 Caption = 'Form1' ClientHeight = 347 ClientWidth = 437 FormFactor.Width = 320 FormFactor.Height = 480 FormFactor.Devices = [Desktop] OnClose = FormClose DesignerMasterStyle = 0 end
单元代码
unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs; type TForm1 = class(TForm) procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.fmx} uses FMX.DialogService.Sync; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin if TDialogServiceSync.MessageDialog( 'Are you sure you want to close?', TMsgDlgType.mtWarning, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], TMsgDlgBtn.mbYes, 0) = mrNo then Action := TCloseAction.caNone; end; end.
解决方案
方案1:改用Windows原生API MessageBox
直接调用Windows API的MessageBox替代TDialogServiceSync.MessageDialog,确保对话框在任何窗体状态下都能正常显示,和VCL程序行为一致:
修改FormClose方法,需在uses中添加Winapi.Windows单元:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); var Result: Integer; begin // 可选:恢复窗体状态提升用户体验 if WindowState = TWindowState.wsMinimized then WindowState := TWindowState.wsNormal; // 指定当前窗体为父窗口,确保对话框正常显示 Result := MessageBox(Handle, 'Are you sure you want to close?', 'Warning', MB_YESNO or MB_ICONWARNING); if Result = IDNO then Action := TCloseAction.caNone; end;
方案2:为TDialogServiceSync指定明确父窗口
如果坚持使用TDialogServiceSync,可手动指定父窗口为当前窗体,并确保窗体激活:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); var DialogResult: TModalResult; begin if WindowState = TWindowState.wsMinimized then begin WindowState := TWindowState.wsNormal; SetForegroundWindow(Handle); // 强制激活窗体 Application.ProcessMessages; end; // 手动传入当前窗体作为对话框Owner DialogResult := TDialogServiceSync.MessageDialog( 'Are you sure you want to close?', TMsgDlgType.mtWarning, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], TMsgDlgBtn.mbYes, 0, Self); if DialogResult = mrNo then Action := TCloseAction.caNone; end;
方案3:在FormCloseQuery中提前拦截关闭请求
将确认逻辑移到FormCloseQuery事件中,更早拦截关闭请求,避免窗体状态导致的对话框隐藏:
- 为窗体添加
OnCloseQuery事件 - 实现事件处理:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); var Result: Integer; begin if WindowState = TWindowState.wsMinimized then WindowState := TWindowState.wsNormal; Result := MessageBox(Handle, 'Are you sure you want to close?', 'Warning', MB_YESNO or MB_ICONWARNING); CanClose := (Result = IDYES); end;
内容的提问来源于stack exchange,提问作者XylemFlow
相关产品推荐
相关产品推荐

