Delphi迁移后如何实现Windows任务栏预览仅展示当前模态窗体
解决方案
无需修改现有窗体逻辑的实现方案
你可以通过全局监听模态窗体的生命周期事件,动态调整窗口的扩展样式实现需求,全程不需要改动现有200个窗体的任何代码,也不需要修改ShowModal调用逻辑,性能无额外损耗。
实现原理
Windows任务栏的缩略图展示规则由窗口的WS_EX_APPWINDOW和WS_EX_TOOLWINDOW扩展样式控制:
- 带
WS_EX_APPWINDOW样式的窗口会单独在任务栏展示缩略图 - 带
WS_EX_TOOLWINDOW样式的窗口不会被任务栏收录展示
我们只需要在模态窗体弹出/关闭时,动态给当前活跃的窗体加WS_EX_APPWINDOW样式,其余窗体加WS_EX_TOOLWINDOW样式,即可实现仅展示当前操作窗体的效果。
具体代码实现
- 首先在主窗体的私有成员区声明变量存储当前活跃模态窗体:
private FLastActiveModal: TForm; procedure ModalBeginHandler(Sender: TObject); procedure ModalEndHandler(Sender: TObject); procedure ActiveFormChangedHandler(Sender: TObject);
- 在主窗体的
OnCreate事件中注册全局监听事件,同时建议在工程文件中设置Application.MainFormOnTaskbar := True保证样式生效更稳定:
procedure TMainForm.FormCreate(Sender: TObject); var ExStyle: LONG_PTR; begin // 注册全局模态窗口监听事件 Application.OnModalBegin := ModalBeginHandler; Application.OnModalEnd := ModalEndHandler; Application.OnActiveFormChange := ActiveFormChangedHandler; // 初始化主窗体样式,默认仅主窗体展示在任务栏 ExStyle := GetWindowLongPtr(Application.MainForm.Handle, GWL_EXSTYLE); ExStyle := ExStyle and not WS_EX_TOOLWINDOW; ExStyle := ExStyle or WS_EX_APPWINDOW; SetWindowLongPtr(Application.MainForm.Handle, GWL_EXSTYLE, ExStyle); end;
- 实现模态窗体弹出的处理逻辑:
procedure TMainForm.ModalBeginHandler(Sender: TObject); var ActiveForm: TForm; ExStyle: LONG_PTR; begin ActiveForm := Screen.ActiveCustomForm as TForm; if not Assigned(ActiveForm) then Exit; // 隐藏上一个活跃窗体的任务栏展示 if Assigned(FLastActiveModal) then begin ExStyle := GetWindowLongPtr(FLastActiveModal.Handle, GWL_EXSTYLE); ExStyle := ExStyle and not WS_EX_APPWINDOW; ExStyle := ExStyle or WS_EX_TOOLWINDOW; SetWindowLongPtr(FLastActiveModal.Handle, GWL_EXSTYLE, ExStyle); end else begin // 首次弹出模态窗时隐藏主窗体的任务栏展示 ExStyle := GetWindowLongPtr(Application.MainForm.Handle, GWL_EXSTYLE); ExStyle := ExStyle and not WS_EX_APPWINDOW; ExStyle := ExStyle or WS_EX_TOOLWINDOW; SetWindowLongPtr(Application.MainForm.Handle, GWL_EXSTYLE, ExStyle); end; // 给当前活跃模态窗开启任务栏展示 ExStyle := GetWindowLongPtr(ActiveForm.Handle, GWL_EXSTYLE); ExStyle := ExStyle and not WS_EX_TOOLWINDOW; ExStyle := ExStyle or WS_EX_APPWINDOW; SetWindowLongPtr(ActiveForm.Handle, GWL_EXSTYLE, ExStyle); FLastActiveModal := ActiveForm; end;
- 实现模态窗体关闭的处理逻辑:
procedure TMainForm.ModalEndHandler(Sender: TObject); var ExStyle: LONG_PTR; NextActive: TForm; begin // 隐藏已关闭模态窗的任务栏展示 if Assigned(FLastActiveModal) then begin ExStyle := GetWindowLongPtr(FLastActiveModal.Handle, GWL_EXSTYLE); ExStyle := ExStyle and not WS_EX_APPWINDOW; ExStyle := ExStyle or WS_EX_TOOLWINDOW; SetWindowLongPtr(FLastActiveModal.Handle, GWL_EXSTYLE, ExStyle); FLastActiveModal := nil; end; // 恢复下一层活跃窗体的任务栏展示 NextActive := Screen.ActiveCustomForm as TForm; if Assigned(NextActive) and (NextActive <> Application.MainForm) then begin ExStyle := GetWindowLongPtr(NextActive.Handle, GWL_EXSTYLE); ExStyle := ExStyle and not WS_EX_TOOLWINDOW; ExStyle := ExStyle or WS_EX_APPWINDOW; SetWindowLongPtr(NextActive.Handle, GWL_EXSTYLE, ExStyle); FLastActiveModal := NextActive; end else begin // 所有模态窗关闭后恢复主窗体的任务栏展示 ExStyle := GetWindowLongPtr(Application.MainForm.Handle, GWL_EXSTYLE); ExStyle := ExStyle and not WS_EX_TOOLWINDOW; ExStyle := ExStyle or WS_EX_APPWINDOW; SetWindowLongPtr(Application.MainForm.Handle, GWL_EXSTYLE, ExStyle); end; end;
- 实现活跃窗体切换的兜底处理逻辑,兼容Alt+Tab切换等特殊场景:
procedure TMainForm.ActiveFormChangedHandler(Sender: TObject); var ActiveForm: TForm; begin ActiveForm := Screen.ActiveCustomForm as TForm; if not Assigned(ActiveForm) then Exit; if (FLastActiveModal = ActiveForm) or (not Assigned(FLastActiveModal) and ActiveForm = Application.MainForm) then Exit; // 强制刷新样式匹配当前活跃窗体 ModalEndHandler(nil); ModalBeginHandler(nil); end;
依赖说明
需要在代码中引用以下单元:
Winapi.WindowsWinapi.DwmApiVcl.FormsVcl.Screen
内容的提问来源于stack exchange,提问作者plexus
相关产品推荐
相关产品推荐

