源起:
近期所介入的几个项目中,最后视频生成窗体,为一模态对话框。因生成时间可能较长,所以其窗体可以最小化,它最小化时同时最小化主程序,唤醒时主程序再复原。
代码亦是8年前本人所写,一直那样用了,也没什么不妥,但总感觉显示效果有优化空间,回头看看当初代码少了些简练。于是用些时间做些验证,寻得相对好点的优化方案。
1、最初实现:
方式是接管模态窗体WM_SYSCOMMAND消息,拦截SC_MINIMIZE窗体最小化消息值进行处理,代码如下:
type TfrmModal = class(TForm) Edit1: TEdit; private { Private declarations } procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND; ... procedure TfrmModal.WMSysCommand(var Msg: TWMSysCommand); begin if Msg.CmdType = SC_MINIMIZE then Application.Minimize else
inherited; end;
此代码工作效果,如下动画:
它有两个问题:
i. 任务栏唤起时,对话框直接显示出来,然后才是主窗体从任务栏上动画出来。
ii. 显示出来后,焦点没有落在它身上,需要点击下主窗体触发,焦点才会移到它上面。
这就是它的瑕疵。可是如何优化呢?
反复调整消息处理次序,并抓取在此过程中它的系统消息,终于找到一个相对好点的方案,如方案2.
2、方案优化
与1大同小异,调整WM_SYSCOMMAND消息处理函数处理机制,并加入WM_SHOWWINDOW消息处理,代码如下:
type TfrmModal = class(TForm) Edit1: TEdit; private { Private declarations } procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND; procedure WMShowWindow(var Msg: TWMShowWindow); message WM_SHOWWINDOW; ... procedure TfrmModal.WMShowWindow(var Msg: TWMShowWindow); begin inherited; if Self.WindowState = wsMinimized then begin Self.WindowState := wsNormal; Application.BringToFront; end; end; procedure TfrmModal.WMSysCommand(var Msg: TWMSysCommand); begin inherited; if Msg.CmdType = SC_MINIMIZE then Application.Minimize; end;
因为没有忽略SC_MINIMIZE消息,此窗体亦被最小化,那么在WM_SHOWWINDOW消息中,对它重唤起。
效果如下图:
两图对比可见,方案1之两点问题,完美解决。