Delphi – How to prevent from loss of focus when showing and/or closing secondary forms from the main form

delphidelphi-2009vclwinapi

Showing 2 secondary forms from the main form and then closing both forms will cause the main form to lose focus. (another application gets activated instead of mine)

The secondary forms are created either by the Main Form directly or by creating the third form from the second form.

The secondary forms set caFree in the OnClose event:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

Using Delphi 2009 (Update 3 & 4) with XP SP3.

Here are my steps for reproducing the problem:

  1. Create a new VCL forms applications
  2. Assign the OnClose event as above
  3. Drag a button onto the created form
  4. In the click handler create a new TForm1 and show it as below

Run the program. Click the button to show a second form. Click the button on the second form to create a third form. When closing both new forms the main form will lose its focus.

This is my code in the button click event handler:

with TForm1.Create(Application) do
    show;

Is there any way to stop my main form from losing focus?

(Interestingly, when creating both secondary forms directly from the Main Form, the issue will only appear when closing the first created form then the second created form)


In the past I had the same issue which was solved by updating my delphi installation, but in that scenario I didn't use caFree in the OnClose event which is the cause for this
bug.

A recommendation to set the Parent property on the secondary forms to Main Form, makes the new forms bounded to the Main Form which I'd rather not have. (and the solution proposed there to always reactivate the Main Form causes the activation order of the forms to be lost)

Best Answer

I would manually activate the 'owning' window with an api call just before one of the forms close:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  SetForegroundWindow(GetWindowLong(Handle, GWL_HWNDPARENT));
end;

This won't be a problem with the OS (i.e. no flashing task bar button) because our application is already in the foreground.

If MainFormOnTaskBar is set, the owning window will be our main form, if not it will be the hidden application window. In either case the application will stay in the foreground.

The SetForegroundWindow call is redundant when closing the last form - the main form, it will even fail if MainFormOnTaskBar is true since then the main form will not be owned, but I wouldn't care it much (then again one can of course include a test before calling it)..

Related Topic