Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 哪一个是初始化代码的最佳位置?_Delphi - Fatal编程技术网

Delphi 哪一个是初始化代码的最佳位置?

Delphi 哪一个是初始化代码的最佳位置?,delphi,Delphi,可能重复: 哪一个是初始化代码(如加载INI文件)的最佳位置?我想首先在屏幕上显示表单,以便用户知道应用程序正在加载,然后我想调用长函数,如LoadInFile或IsConnectedToInternet(最后一个非常慢) OnCreate不好,因为表单还没有准备好,它不会显示在屏幕上 我在DPR中这样做,但不总是工作: program Test; begin Application.Initialize; Application.Title := 'Test app'; App

可能重复:

哪一个是初始化代码(如加载INI文件)的最佳位置?我想首先在屏幕上显示表单,以便用户知道应用程序正在加载,然后我想调用长函数,如LoadInFile或IsConnectedToInternet(最后一个非常慢)

OnCreate不好,因为表单还没有准备好,它不会显示在屏幕上

我在DPR中这样做,但不总是工作:

program Test;
begin
  Application.Initialize;
  Application.Title := 'Test app';
  Application.CreateForm(TfrmTest, frmTest);
  frmTest.Show;               <---------------------- won't show
  LateInitialize;
  Application.Run;
end.
程序测试;
开始
应用程序初始化;
应用程序名称:=“测试应用程序”;
Application.CreateForm(TfrmTest、frmTest);

第一次测试显示 很久以前,在另一个遥远的论坛上,有人发布了以下内容来记录表单的生命周期。我发现它很有用,所以我在这里分享它

Create       OnCreate
Show         OnShow
Paint        OnPaint
Activate     OnActivate
ReSize       OnResize
Paint        OnPaint

Close query  OnCloseQuery
Close        OnClose
Deactivate   OnDeactivate
Hide         OnHide
Destroy      OnDestroy

尝试OnActivate事件。

在调用
frmTest.Show
后,您可以调用
frmTest.Update
使其呈现在屏幕上,然后再调用
LateInitialize
。但是,在调用
Application.Run
之前,主消息循环将不会运行,因此在此之前表单将无法执行任何其他操作

另一个选项是使用表单的
OnShow
事件,通过
PostMessage()
将自定义窗口消息发布回表单,然后在稍后收到该消息时让表单调用
LateInitialize
。这将允许窗体正常处理绘制消息,直到调用
LateInitialize


任何阻塞主线程超过几毫秒/秒的线程都应该移到单独的工作线程中(特别是像
isconnectedpointernet
)。主线程应该用于运行UI。

变体1:使用TTimer,延迟1秒,从主窗体的OnShow运行它 在TTimer中进行初始化 这将为大多数组件提供初始化和绘制它们自己的时间 变体1.1:在函数中使用message方法,并从OnShow调用Win API PostMessage(但不是SendMessage aka Perform)。这是相似的,但更便宜,更快。然而,在表单上的某个复杂组件完全绘制自身之前,有时可能会收到消息“DoInit now”

变体2:使用线程(OmniThreadsLib或甚至是纯TThread) 从mainformoncreate启动它,让它在后台准备所有数据,然后启用所有需要的按钮、菜单等 如果你有长函数和阻塞函数,这确实是最好的方法,liek,你描述的是连接到Internet

变体3:在显示主窗体之前使用SplashScreen。 这很好,因为用户看到应用程序尚未读取。
正是因为这个原因,这是不好的——人们开始觉得你的程序很慢。Google Chrome被告知在第一个瞬间将其主要形式绘制为图片,只是为了看起来“我们已经开始了”,即使实际控制也会在稍后准备就绪。

一个简单的方法是向自己发送消息。 我总是这样做

const
  MSG_AFTERCREATE = WM_APP + 4711;

...
procedure OnCreate(Sender: TObject);
procedure AfterCreate(var message: TMessage); message MSG_AFTERCREATE;
...


Implementation

procedure OnCreate(Sender: TObject);
begin
  PostMessage(Self.Handle, MSG_AFTERCREATE, 0, 0);
end;

procedure AfterCreate(var message: TMessage);
begin
  //Do initializing here... the form is done creating, and are actually visible now...
end;

那些帖子没有被接受的答案,它们完全是在同一个主题上。嗯,是的。这是一个有绿色大对勾和三张赞成票的。是的,他们在同一个问题上。你的问题也是,这就是为什么我把它标记为a。如果它们完全在同一个主题上,那么你自己承认它们完全是这个问题的复制品。他们是否接受了答案并不重要。“重复”是问题的属性,完全独立于可能存在的任何答案。然而,这两个问题都得到了答案。如果你的问题已经在这里被问到了,但是他们没有合适的答案来回答你的情况,那么有一些方法可以引起人们对这些问题的注意,这样人们就会回答他们。问一个重复的问题只是其中一种方式。我不确定这一点,但我认为如果您将DPR切换到ShowModal而不是Show,并在单独的线程中执行剩余的负载,它将像一个符咒一样工作。我记得在我以前的Delphi项目中使用了类似的东西,但那是很久以前的事了…@Ken-Oh。。。抱歉,它确实有一个可接受的答案。但是请记住,
OnActivate
可以在程序过程中多次触发。-1。每当表单失去焦点然后再次获得焦点时(例如,用户单击应用程序中的另一个表单,或切换到其他应用程序,然后返回到您的应用程序),OnActivate就会触发。除非您的初始化代码可以运行多次,否则OnActivate绝对是放置它的错误位置。@Rob Kennedy&Ken White:你们是专家,所以我将听从您的高明。然而,我一直在做类似的事情(但更多的是在OnShow活动中)。我只是添加了一个标志变量来指示初始化代码是否已运行。如果发生了初始化,我将跳过初始化代码。他问初始化代码放在哪里,而不是如何编码。OnActivate只能通过将
OnActivate:=nil在OnActivate事件中。谢谢Max和Blobby。一个非常优雅和卓越的解决方案!变量1:如果CPU是,主窗体没有时间进行自我更新,但TTimer上的时间已过期(第二次过期),该怎么办?变量2:在初始化过程中,我必须进行大量GUI(INI文件)和全局变量初始化。线程将与主窗体进行大量交互。1)据我所知,WM_定时器系统消息已发布,迟早会得到解决。但您可以简单地对其进行测试—将计时器设置为10秒,并使用SysInternals ProcessExplorer将程序挂起20秒,然后看看会发生什么。2)坦率地说,我不明白为什么INI文件是GUI也许你要让updatePart1/UpdatePart2/。。。事件,这样线程将加载这些变量的某些部分并发送它们,这样主窗体将重新读取那些已经初始化的变量。但这需要将您的程序拆分为
const
  MSG_AFTERCREATE = WM_APP + 4711;

...
procedure OnCreate(Sender: TObject);
procedure AfterCreate(var message: TMessage); message MSG_AFTERCREATE;
...


Implementation

procedure OnCreate(Sender: TObject);
begin
  PostMessage(Self.Handle, MSG_AFTERCREATE, 0, 0);
end;

procedure AfterCreate(var message: TMessage);
begin
  //Do initializing here... the form is done creating, and are actually visible now...
end;