如何避免两次调用Application.CreateForm?

时间:2010-02-01 07:28:37

标签: delphi delphi-2007

我偶然发现了这个页面Why shouldn’t I call Application.CreateForm。 现在我有一些像这样的代码:

SplashForm := TSplashForm.Create(Application);
SplashForm.Show;
SplashForm.Update; // force update
Application.Initialize;
Application.CreateForm(TClientData, ClientData);
SplashForm.Update; // force update
Application.CreateForm(TClientMainForm, ClientMainForm);
Application.ShowHint := True;

Application.Run;
ClientMainForm.ServerConnected := false;
FreeAndNil(ClientMainForm);
FreeAndNil(ClientData);

首先创建一个splashform,然后创建一个datamodule并最后一个主窗体。页面说不应该调用Application.CreateForm两次。上面的代码应该改变吗?

4 个答案:

答案 0 :(得分:5)

多次使用Application.CreateForm没有任何问题。但是这会为每种形式引入全局变量,这些变量可能是代码气味。 不幸的是,IDE为每个表单创建一个。虽然你可以删除它们。

更好的方法是在需要时创建表单,并在准备就绪时将其释放。因此,您只能将Application.CreateForm用于主窗体。

主数据模块可以由主表单创建。但它也可以是全球性的,只是一种品味问题。

因此,要回答这个问题,您可以通过在本地创建和发布表单来避免Application.CreateForm。

文章提到Application.CreateForm的副作用(第一个完成的表单是主窗体)。 因此,如果主窗体使用Application.CreateForm创建其他窗体,则可能会出现意外的副作用。

所以为了避免任何讨厌,你应该将yoursef限制为一次通话。这只使用一种全局形式完成。

答案 1 :(得分:1)

如果TClientData是一个数据模块而TClientMainForm是一个表单,那么没有(除了最后两个FreeAndNil调用 - 不是真的需要)。但要小心。因为正如Rob Kennedy在帖子中所说的那样,Application.CreateForm会做其他事情(它设置 MainForm 变量),所以我建议根据以下规则设置项目文件: / p>

  1. 使用单次调用创建在启动时创建的所有表单到Application.CreateForm - 通常由IDE完成。

  2. 从项目文件中删除要在程序中动态(按需)创建的表单。 (在项目|选项|表单中...) - 将它们从“自动创建表单”移动到“可用表单”

  3. 使用 TmyForm.Create(所有者)(等)在 代码中创建表单,使用 Application.CreateForm(...)。顺便说一句,如果您确定要释放表单,那么最好(为了加快速度)调用 TmyForm.Create( nil - 没有任何所有者的情况。

  4. 如果你想在启动时进行某种初始化,你可以在项目文件中有一个与已经创建的表单/数据模块绑定的过程/方法,并在应用程序运行之前运行它。

  5. 例如:

    begin 
      Application.Initialize; 
      Application.MainFormOnTaskbar := True; 
      Application.CreateForm(TdmoMain, dmoMain); //<--this is a data module
      Application.CreateForm(TfrmMain, frmMain); //<--this will became the main form
      Application.CreateForm(TfrmAbout, frmAbout);
      //... other forms created here...
      frmMain.InitEngine; //<--initialization code. You can put somewhere else, according with your app architecture
      Application.Run;
    end.
    

    通过这种方式,您可以清理项目文件,并确切知道哪个是。

    HTH

答案 2 :(得分:1)

当我写这篇文章时,我主要考虑的是代码之外的DPR文件。人们在DPR文件中看到IDE生成的表单创建代码,并认为这是创建表单的最佳方式,因此他们在程序的其他地方使用它。他们有时在主窗体的OnCreate事件处理程序中使用它来创建程序需要的其他表单,然后它们遇到问题,因为程序的主要表单不是他们认为的那样。

在您提供的代码中,只需调用一次CreateForm即可。将它用于主表单,而不是其他任何内容。数据模块不是主要形式,因此您不需要CreateForm的魔力。

SplashForm := TSplashForm.Create(Application);
SplashForm.Show;
SplashForm.Update; // force update
Application.Initialize;

// Change to this.
ClientData := TClientData.Create(Application);

SplashForm.Update; // force update
Application.CreateForm(TClientMainForm, ClientMainForm);
Application.ShowHint := True;

Application.Run;
ClientMainForm.ServerConnected := false;

// Remove these.
FreeAndNil(ClientMainForm);
FreeAndNil(ClientData);

你真的不应该释放你在这里创建的对象,因为你没有拥有它们。它们由全局Application对象拥有,因此请让它们释放它们:删除对FreeAndNil的两个调用。

答案 3 :(得分:0)

您引用的文章不正确。您需要多次调用Application.CreateForm

的原因有很多

1)数据模块:您可能希望所有这些都可用。最好的方法是Application.CreateForm。我知道有几个主题数据模块的应用程序,例如客户,发票,地址处理数据库的不同区域&amp;整齐地封装功能。所有这些都是在.dpr

中创建的

2)大而缓慢的加载(这本身就是一个坏主意,但这些事情发生并且通常由支持程序员继承......)。将加载时间移动到应用程序启动中,与示例代码一样,同时更新启动画面。用户期待应用程序需要一段时间才能开始工作,这要归功于我们的同事在Microsoft Office上工作,以降低对我们其他人的期望:)

所以,总而言之,不要担心你的代码很好 - 但你可能会失去“FreeAndNil”的东西。然而,小型快速击中Dialog类型的东西最好由以下方式调用:

with TMyform.Create(nil) do
try
  //Setup
  case ShowModal of
    // Whatever return values you care about (if any)
  end;
finally
  Free;
end;

简短,甜蜜,至关重要。最小化内存使用...