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

发布于 2024-08-19 19:31:38 字数 667 浏览 7 评论 0原文

我偶然发现了这个页面为什么我不应该调用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);

首先创建一个启动表单,然后创建一个数据模块,最后创建主表单。该页面指出 Application.CreateForm 不应被调用两次。上面的代码应该修改吗?

I stumbled on this page Why shouldn’t I call Application.CreateForm.
Now I have some code like this:

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);

First a splashform is created, then a datamodule and last the main form. The page says that Application.CreateForm should not be called twice. Should the code above be changed?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

甜心 2024-08-26 19:31:38

多次使用Application.CreateForm并没有什么问题。但这会为每个表单引入全局变量,这可能会产生代码味道。
不幸的是,IDE 为每个表单创建一个。尽管您可以根据需要删除它们。

更好的方法是在需要时创建表单,并在准备好时释放它。所以你只使用Application.CreateForm作为主窗体。

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

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

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

因此,为了避免任何麻烦,您应该将自己限制为一次调用。这是仅使用一种全局形式来完成的。

There is nothing wrong with using Application.CreateForm multiple times. But this introduces global variables for each form which can be a code smell.
Unfortunately the IDE creates one for each form. Although you can remove them if you like.

A better way is to create a form when you need it and release it when you are ready with it. So you only use Application.CreateForm for the main form.

A main datamodule can be created by the main form. But it can be global too, just a matter of taste.

So to answer the question, you can avoid Application.CreateForm by creating and releasing the forms locally.

The article mentions the side effect of Application.CreateForm (the first completed form is the main form).
So there can be unexpected side effects if the main form creates other forms using Application.CreateForm.

So just to avoid any nastyness, you should limit yoursef to a single call. Which is done using only one global form.

不念旧人 2024-08-26 19:31:38

如果 TClientData 是一个数据模块并且 TClientMainForm 是一个表单,那么就不需要(除了最后的两个 FreeAndNil 调用 - 并不是真正需要的)。但要小心。因为正如 Rob Kennedy 在他的文章中所说,Application.CreateForm 会在后面执行其他操作(它设置 MainForm 变量),所以我建议根据以下规则设置项目文件:

  1. < p>使用对 Application.CreateForm 的单次调用来创建您想要在启动时创建的所有表单 - 通常这由 IDE 完成。

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

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

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

例如:

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.

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

华泰

If TClientData is a Data Module and TClientMainForm is a form, then no (except perhaps the two FreeAndNil calls at the end - not really needed). But take care. Because as it says Rob Kennedy in his post, the Application.CreateForm does other things behind (it sets the MainForm variable), so I would advise to set up your project file according to the following rules:

  1. Create all the forms which you want to create at startup using a single call to Application.CreateForm - usually this is done by the IDE.

  2. Remove from the project file the forms which you want to create dynamically (on-demand) in your program. (In Project | Options | Forms...) - move them from 'Auto-Create Forms' to 'Available Forms'

  3. Create your forms in your code using TmyForm.Create(Owner) (etc.) and not with Application.CreateForm(...). As an aside, if you are sure that you will free the form, then it is better (in order to speed the things up) to call TmyForm.Create(nil) - iow without any owner.

  4. If you want to do some kind of initialization at startup you can have a procedure / method in the project file tied to a form / data module already created and run it before application run.

For example:

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.

In this way you will have the project file clean and you will know exactly which is which.

HTH

夜灵血窟げ 2024-08-26 19:31:38

当我写那篇文章时,我主要考虑的是 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 的两个调用。

When I wrote that article, I was thinking primarily of code outside the DPR file. People see the form-creation code generated by the IDE in the DPR file and think that's the best way to create forms generally, so they use that elsewhere in their programs. They sometimes use it in the main form's OnCreate event handler to create other forms their program needs, and then they hit problems because the program's main form isn't what they think it is.

In the code you provided, it's easy to call CreateForm just once. Use it for the main form, and for nothing else. The data module isn't a main form, so you don't need CreateForm's magic there.

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);

You really shouldn't free the objects you've created here because you don't own them. They're owned by the global Application object, so let it take care of freeing them: Remove the two calls to FreeAndNil.

孤星 2024-08-26 19:31:38

您引用的文章不正确。您希望多次调用 Application.CreateForm 的原因有很多。

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

2) 大的、加载缓慢的东西(这本身就是一个坏主意,但这些事情发生并且经常被支持程序员继承......)。将加载时间移至应用程序启动中,就像示例代码以及闪屏更新一样。用户期望应用程序需要一段时间才能运行,这要归功于我们从事 Microsoft Office 工作的同事们做出的巨大努力,以降低我们其他人的期望标准:)

因此,总而言之,不要'不用担心你的代码没问题 - 但你可能会丢失“FreeAndNil”的东西。然而,小型快速点击对话框类型的内容最好通过以下方式调用:

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

简短、甜蜜、切中要点和内容。最大限度地减少内存使用...

The article you refer to is incorrect. There are a number of valid reasons why you would want multiple calls to Application.CreateForm

1) Datamodules: You probably want these available all of the time. Best way to do this is Application.CreateForm. I know of applications with several themed Datamodules e.g. Customer, Invoice, Address to handle different areas of the database & encapsulate the functionality neatly. All of these are created in the .dpr

2) Big, slow loading stuff (which is a bad idea in & of itself but these things happen and are often inherited by support programmers...). Move the load time into the application startup exactly like your example code along with the splash screen updating. The users expect applications to take a while to get going thanks to the stirling efforts of our collegues working on Microsoft Office to lower the bar of expectations for the rest of us :)

So, in summary, don't worry your code is fine - but you can lose the "FreeAndNil" stuff. However small quick hitting Dialog type stuff is best invoked by:

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

Short, sweet, to the point & minimises memory usage...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文