我会提出一种与
Server Overflow的这个答案略有不同的方法。我们将实现几乎完全相同的效果,但不需要在DPR文件(主项目源文件)内进行任何编辑。我们将通过在主窗体单元中使用类助手来实现目标:
type
TAppHelper
= Class helper for TApplication
Public Procedure Run;
End;
Procedure TAppHelper.Run;
begin
Unit1.MainForm.PreRun;
inherited Run;
end;
注意,Unit1.MainForm.PreRun是您主窗体中的某个方法,只有一个限制条件:如果您的主窗体被称为“MainForm”,那么您需要在帮助器方法中添加您单位名称的前缀,因为TApplication类已经有一个成员叫做MainForm。顺便说一下,如果您确实省略了前缀,这可能仍然有效,因为您的Unit1.MainForm确实也是应用程序的主窗体。
这种方法之所以有效,是因为Unit1在DPR项目的uses列表中,并且只要TAppHelper在接口部分(而不是实现部分)中定义,它就会被加载,当在DPR文件中调用Application.Run方法时,这将已经是其帮助器版本。
这样做的美妙之处在于,它只会运行一次,并且在所有窗体都已经创建并且它们的构造函数已经执行后运行。事实上,我们有效地定制了DPR文件中的Application.Run调用,而不需要编辑DPR文件,这有点巧妙。再次强调,Delphi/Lazarus中的类帮助器!
我还会分享一个很棒的技巧,请先看一下:
Procedure TAppHelper.Run;
begin
TTask.Run(
procedure
begin
sleep(10);
TThread.Synchronize(nil, procedure begin Unit1.MainForm.PreRun; end);
end
);
inherited Run;
end;
这是我在想让代码延迟执行时使用的技巧。为什么呢?因为如果你的代码在继承的Run方法之前运行,它可能会(取决于该代码内部发生了什么)暂时挂起UI,但足以使窗体在启动期间闪烁并出现无响应。此外,我们不能简单地将代码放在继承的Run方法后面,因为直到应用程序被终止才会执行。所以我使用System.Threading单元中的TTask。sleep(10)可能有些过度,sleep(1)很可能就能完成任务,甚至根本不需要休眠,但我在那里做了一些复杂的初始化,所以我保持了较长的延迟时间。额外的好处是:如果你没有从PreRun自定义方法更新UI,那么你甚至不需要TThread.Synchronize包装器,它变得更加简单。在FPC/Lazarus的情况下,你可以使用
TApplication.QueueAsyncCall()代替TTask类来实现相同的效果。
我真的认为这是一个很棒的技巧,因为我可以完全在定义PreRun方法的窗体单元之外编写代码,并且保证在所有窗体都已创建之后执行,而不仅仅是实现PreRun方法的那个窗体。而且,如果类助手在窗体单元中而不是其他地方,那么PreRun甚至不需要是公共的,它也可以使用受保护的或甚至是私有的方法!这对于将这个小逻辑与代码的任何其他部分分开非常有用。