How do I avoid to call Application.CreateForm twice?

好久不见. 提交于 2019-12-23 09:56:05

问题


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?


回答1:


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.




回答2:


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




回答3:


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.




回答4:


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...



来源:https://stackoverflow.com/questions/2175253/how-do-i-avoid-to-call-application-createform-twice

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!