Sky
Sky

Reputation: 4370

A form creates twice on application's FormCreate event

I'm trying to load a form when my main form starts. And I do it using ShowModal. Also that form is not an auto create form so I have to create it first with application.CreateForm.

My problem is when I try to load the form in FormCreate event, it load the form twice and when I close the form my whole app closes.

Here is my code:

procedure Tfrm_main.FormCreate(Sender: TObject);
var
  username, password : string;
begin
  username := ini.ReadString('user','username','');
  if username = '' then
  begin
    application.CreateForm(Tfrm_user,frm_user);
    frm_user.ShowModal;
  end;
end;

How can I fix this problem? Thanks.

Upvotes: 2

Views: 437

Answers (2)

David Heffernan
David Heffernan

Reputation: 612954

The code in your question is called from the call to Application.CreateForm that creates the main form. Then you call Application.CreateForm again, recursively, and that results in the Tfrm_user instance becoming the main form.

It's well known that the first form created by Application.CreateForm becomes the main form. Here, you call Application.CreateForm to create the main form. But before the code of Application.CreateForm gets to determine what the VCL considers to be the main form, the recursive call to Application.CreateForm executes. All the way to the end, and in doing so determines the main form to be the secondary form made with the recursive call.

You then show the secondary form modally. Later you call Application.Run which shows the VCL main form, your secondary form. Again. And then you close it. Which closes the program, because that's what happen when you close the VCL main form.

My advice is to call Application.CreateForm exactly once in the life of your program. So, in the OnCreate handler create the other form like this:

frm_user := Tfrm_user.Create(Application);

Or perhaps let the main form be the owner. And certainly consider not using the global variable frm_user. I'd remove that.

Or another option would be to show the secondary form modally before you make the call to Application.CreateForm.

Upvotes: 6

Mason Wheeler
Mason Wheeler

Reputation: 84550

You're getting bitten by an order-of-operations issue.

If you look at the code to TApplication.CreateForm, you'll see that things happen in this order:

  • Create a new form of the appropriate type.
  • If FMainForm = nil, assign this new form to it.
  • Later, TApplication.Run calls FMainForm.Show;

But when the program is setting up your principal form:

  • It first creates it, which calls the OnFormCreate event handler. Then the event handler calls TApplication.CreateForm, (before the first one has returned) which creates the new form, sees that FMainForm is not assigned and assigns this form to it, then returns.
  • Your FormCreate then shows this form as a modal, then returns.
  • Things unwind a little, and we're back to the original TApplication.CreateForm, which goes on to the next part, sees FMainForm already assigned, and does not assign it.
  • Then it returns, and TApplication.Run gets called, which shows the main form... the wrong one.

IF you want to create the new form, call the constructor instead: frm_user := Tfrm_user.Create(Application); Really, TApplication.CreateForm should only be used the one time, to set up the main form. It's kind of a hack that can make trouble for you if you don't know exactly how it works.

Upvotes: 5

Related Questions