Jump to content
Ian Branch

Form closing - curiosity question..

Recommended Posts

Hi Team,

I run an App inactivity/idle routine in the background.  The objective is that if the App is idle, no keyboard or mouse activity for x minutes, the App closes.

Closure is generally by closing the Main form.

So, I was wondering, what does Delphi do if you are in a second form opened from the main form when the idle triggers?

Does it formally/gracefully close the second form first, and by extension any other forms open in the App, then close the main form, or does it simply close the main form and crash the second, and any other, form?

I guess a follow up to that, if it does close other forms gracefully first, what dictates the order of closure?

Regards & TIA,

Ian

Edited by Ian Branch

Share this post


Link to post

When the MainForm is closed the application is terminated. That implies that all forms created with Application as owner will be destroyed, but not closed (so OnDestroy is called, but not OnClose). The order depends on the components order inside Application. Any form created without an Owner will just vanish.

Share this post


Link to post

Well, closing the main form ends up calling Application.Terminate, which results in a WM_QUIT message posted to the message loop. The reaction to that is to set Application.Terminated to true and fall out of the message loop in Application.Run. After that the Application object proceeds to free all forms and datamodules it ownes in the inverse order of creation.

Things are unfortunately not always so clear, though. If a modal form is open it uses its own message loop, which also ends and causes ShowModal to return as if the user cancelled the dialog. Code in the calling method will execute after that until the code flow returns to the main message loop.

A further complication are unowned forms. They will get destroyed after the owned forms when the main form window handle is destroyed, as far as I remember, by Windows, since the main form is the API-level owner of all secondary forms. Unowned Forms disconnected from the main form by overriding CreateParams will die last (unless explicitely closed in code executed when another form is destroyed), when the process dies. This usually does not give the form any chance to clean up after itself.

So, if you need to have all forms die in an orderly manner you are best served by iterating over Screen.Forms and close each form found explicitely, with the main form last.

Share this post


Link to post

Uwe & Peter, thank you for your responses.  I had suspected as much.

Peter..

9 hours ago, PeterBelow said:

Screen.Forms and close each form found explicitely, with the main form last.

And how does one do that??  I think I have seen that somewhere but I don't recall where. 😞  

Is it done from within the MainForm OnClose event?

 

Regards & TIA,

Ian

Share this post


Link to post

Hi Team,

I have worked up the following code..

procedure TMainForm.CloseOpenForms;
var
  TheForm: TForm;
  I: Integer;
begin
  //
  for I := 0 to Screen.FormCount - 1 do
  begin
    TheForm := Screen.Forms[I];
  //
{$IF  Defined(ELogging) or Defined(Codesite)}
  LogMessage('Form Name = '+ TheForm.Name);
{$ENDIF}
  //
  if TheForm.Name <> 'MainForm' then TheForm.Close;
  //
  end;
end;

It turns out that MainForm is the first in the order of Screen.Forms so if I don't filter it out I end up in a loop. 🙂

Seems to work well.  Open to any suggestions to improve it.

 

Regards,

Ian

Edited by Ian Branch

Share this post


Link to post
2 hours ago, Ian Branch said:

It turns out that MainForm is the first in the order of Screen.Forms so if I don't filter it out I end up in a loop.

The order of Screen.Forms is last used so you could use downto to avoid the active form at forms[0]. 

 

By setting the forms owner to application when creating and only coding FormCloseQuery when necessary allows no need to code the close event of each form.  

 

Pat 

 

 

Share this post


Link to post

Hi Pat,

27 minutes ago, Pat Foley said:

The order of Screen.Forms is last used so you could use downto to avoid the active form at forms[0]. 

Good point.

27 minutes ago, Pat Foley said:

By setting the forms owner to application when creating and only coding FormCloseQuery when necessary allows no need to code the close event of each form. 

I'm not sure I understand what you are saying here??  I have no special handling in the sub-forms.

I have the CloseOpenForms being called in the FormClose of the MainForm.

e.g.  

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  //
  CloseOpenForms;	//  Close any open forms.
  //
  DBC1.CloseDataSets;	//	Close any open tables/Queries.
  //
  DBE1.Close;	//	Close the DB Engine
  //
end;

In the context of this, is a Datamodule considered a Form?

 

Ian

Edited by Ian Branch

Share this post


Link to post

I am saying to use FormCloseQuery in the MainForm and not code any FormClose. Any Freeing is done in a FormDestroy.   Avoiding the need for troublesome ScreenForm OnClose iteration.

 

 

 

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×