Delphi 10.4.2 FMX项目如何检测进入后台及处理浮动窗口置顶问题
核心问题根因
原实现失效的本质是混淆了单窗体焦点事件和应用级前后台事件的触发逻辑:
- 主窗体的
OnDeactivate事件,仅在该主窗体自身从激活态变为非激活态时触发 - 当浮动工具窗持有应用内焦点时,主窗体全程未获得过焦点,从未进入激活态,自然不会触发对应的
Deactivate回调——这就是你切换到外部应用时,浮动窗置顶状态无法被取消的根本原因。
正确实现方案
Delphi 10.4.2 的 FMX 框架提供了进程级的应用前后台回调接口,不需要逐窗体绑定焦点事件,就能稳定捕获整个应用的前后台状态变化。
实现步骤
- 删除原主窗体DFM上绑定的
OnActivate、OnDeactivate事件关联,同时删除主窗体单元里对应的两个事件处理方法 - 在主窗体的创建逻辑中,给全局
Application对象绑定应用级状态回调,参考代码如下:
unit MainForm; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls; type TMainWindow = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private // 新增应用级回调处理方法 procedure AppBecomeForeground(Sender: TObject); procedure AppEnterBackground(Sender: TObject); public { Public declarations } end; var MainWindow: TMainWindow; implementation {$R *.fmx} uses FloatingForm; procedure TMainWindow.FormCreate(Sender: TObject); begin // 绑定应用级前后台事件,覆盖进程全状态 Application.OnActivate := AppBecomeForeground; Application.OnDeactivate := AppEnterBackground; end; procedure TMainWindow.AppBecomeForeground(Sender: TObject); begin // 应用回到前台时,加判空避免浮动窗未初始化引发异常 if Assigned(FloatingToolWindow) then FloatingToolWindow.FormStyle := TFormStyle.StayOnTop; end; procedure TMainWindow.AppEnterBackground(Sender: TObject); begin // 应用进入后台时,无论当前焦点在哪个应用内窗体,统一取消浮动窗置顶 if Assigned(FloatingToolWindow) then FloatingToolWindow.FormStyle := TFormStyle.Normal; end; procedure TMainWindow.Button1Click(Sender: TObject); begin FloatingToolWindow.Show; end; end.
- 调整浮动窗的设计期配置:把浮动窗DFM里硬编码的
FormStyle = StayOnTop删掉,改成默认Normal状态,所有置顶逻辑都通过应用级回调动态控制。
方案有效性说明
- 该回调的触发逻辑和操作系统的应用前后台判定完全对齐:只要整个进程从前台激活状态切到后台非激活状态,无论当前持有焦点的是主窗、浮动窗还是任何其他应用内窗体,
OnDeactivate都会稳定触发 - 完全覆盖原复现场景:浮动窗持有焦点时点击外部应用,应用的
OnDeactivate会正常执行,自动把浮动窗的置顶状态取消,不会再出现悬浮在其他应用之上的问题 - Windows、macOS双平台下的触发行为一致,不存在单窗体事件的触发盲区
内容的提问来源于stack exchange,提问作者Mike at Bookup
相关产品推荐
相关产品推荐

