2

可能重复:
启动画面以编程方式
在数据库连接(可能需要很长时间)运行时显示启动画面

初始化代码(例如加载 INI 文件)的最佳位置是哪个?我想首先在屏幕上显示表单,以便用户知道应用程序正在加载,然后才想调用冗长的函数,如 LoadIniFile 或 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.

在执行 LateInitialize(4-5 秒)之前,表单不会显示。


procedure LateInitialize;
begin
 CursorBussy;
 TRY
  // all this won't work also. the form won't show
  frmTest.Visible:= TRUE;
  Application.ProcessMessages; 
  frmTest.Show;
  Application.ProcessMessages;
  frmTest.BringToFront;
  frmTest.Update;
  Application.ProcessMessages;

  DoSomethingLengthy;     {4-5 seconds}
 FINALLY
  CursorNotBussy;
 END;
end;     <--------- Now the form shows.

是的,frmTest 这是我唯一的形式(主要形式)。

4

4 回答 4

3

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

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

任何阻塞主线程超过几毫秒/秒的东西真的应该被移到一个单独的工作线程中(尤其是像这样的东西IsConnectedToInternet)。主线程应该用于运行 UI。

于 2012-07-27T01:24:34.797 回答
2

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

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;
于 2012-07-27T08:39:51.677 回答
1

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

变体 2:使用线程(OmniThreadsLib 甚至普通 TThread)从 MainForm OnCreate 启动它,让它在后台准备所有数据,然后启用所有需要的按钮、菜单等如果你有长的和阻塞的功能,这确实是最好的方法,liek您描述了 IsConnectedToInternet。

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

于 2012-07-27T07:44:32.053 回答
0

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

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

Close query  OnCloseQuery
Close        OnClose
Deactivate   OnDeactivate
Hide         OnHide
Destroy      OnDestroy

尝试 OnActivate 事件。

于 2012-07-27T00:16:27.350 回答