4
votes

In two parts of my application, the main form gets focussed at the wrong moment:

Bug 1. When clicking 'OK' from a specific printer form.

  1. I open a FastReports PDF preview - that's the first popup. That popup is not shown seperately in the taskbar. This form is modal.
  2. Then I click print,
  3. That opens another window with standard printing options.
  4. Then I click properties - that opens the specific form of the driver. I change the double printing setting.
  5. When I click 'OK', the preview form (1) should be focussed, but the main form is brought to front. Because the preview form is still modal, it is hard to get back to the preview form. Only with random clicks, the preview form gets focussed again.

clicking through


Bug 2. Clicking on or dragging this specific scrollbox focusses the main form

  1. This window is active. This is a seperated window in the Windows task bar and is not modal. There is a gnostice pdf viewer on this form.
  2. When I click the scrollbox to start dragging, the main form is brought to front. When I keep dragging, the scrolling at the pdf form still continues. Also, a tooltip near the mouse indicates what page is currently shown.

Bug 2

I want to solve this strange behaviour. So, my question is:


What can be causing these focussing bugs?


About the application:

  • I already noticed: the popup forms seems a bit too large, as you can see here: form seems to large
  • see edit
  • Some forms are MDI child.
  • I searched in the code for all mouse events and put there breakpoints. But that code was not executed at the moment of the two bugs.
  • VCLskin is used.
  • Bug 1 occurs with Fast reports version 5.6.1 and 5.6.8.
  • Windows 10.
  • Delphi XE 10.2.

Edit

  • The application main form is set correctly. At startup, first a login form is shown. After your login, the datamodules are created, some forms are created without a owner (they are freed on application end).

All other forms, also the main form are owned by Application and not by the Login form. And indeed not as parent, but as owner, like @uwe-raabe said.

Then the main form is created. This is created via the Login form:

Frm_DatabaseLogin.CreateForm(TFrm_MainMenu, Frm_MainMenu);

That calls:

procedure TFrm_DataBaseLogin.CreateForm(InstanceClass: TComponentClass;
  var Reference);
begin
  Updateprogress(InstanceClass.ClassName);
  Application.CreateForm(InstanceClass,Reference);
end;

In UpdateProgress nothing special happens.

After that, the other forms are created too, owned by application. At the end, the login form hides and therefore the main form is shown.

1
"Then the main form is created. It's parent is the login form." That sounds quite strange to me. Do you mean "owner" instead of "parent"? Also the owner of the Mainform is usually Application and the Mainform is created in the DPR with a call to Application.CreateForm. Can you show your code to create these forms?Uwe Raabe
While this question might really be interesting, how would one answer this without the applications code? With ideas for debugging? Look at TWinControl.SetZOrderPosition, TWinControl.WMSetFocus and TCustomForm.WMActivate maybe. Using breakpoints in e.g. WMSetFocus that actually break might alter execution, as focus changes between your application and the IDE occur. For WMSetFocus and SetZOrderPosition I would use a breakpoint condition, like Self is TCustomForm.nil
Quite generalized question with quite specific background. "What can be causing these..." ... Faulty code perhaps... at some place which we cannot see.Sertac Akyuz

1 Answers

0
votes

I'm making some assumptions here on your startup code.

"Main Form" can be a confusing term. From the TApplication point of view Application.MainForm is always the first form that is created using Application.CreateForm.

Since your login form creates your application's primary form and then hides itself, the login form is still the "main" form.

Your screenshot has two icons shown on the taskbar. I'm assuming you are either orverriding CreateParams or calling SetWindowLong to make that happen.

I have a similar setup with a "main" login form that is then hidden.

In my application, I override CreateParams for forms that should be standalone and have a taskbar icon:

procedure TMgrMain.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
  Params.WndParent := 0;
end;

Then when showing popups I create the form with an owner (probably not needed), and then set PopupMode and PopupParent. Since I started this I no longer have forms that pop-behind.

procedure ShowAbout(Owner: TForm);
var
  LocalForm: TAbout;
begin
  LocalForm := TAbout.Create(Owner);
  try
    LocalForm.PopupMode := pmExplicit;
    LocalForm.PopupParent := Owner;
    LocalForm.ShowModal;
  finally
    FreeAndNil(LocalForm);
  end;
end;

From the PopupParent help:

If the PopupMode property is set to pmExplicit and PopupParent is nil, then the Application.MainForm is implicitly used as the PopupParent. If no Application.MainForm is assigned, then Application.Handle is used as the PopupParent.

If the PopupMode property is set to pmAuto, Screen.ActiveForm is used as the PopupParent property.

Part of where I took my steps from were from an old Peter Below newsgroup post. Also this is really old advice now and was before the addition of PopupParent/PopupMode

Newsgroups: borland.public.delphi.winapi
From: "Peter Below (TeamB)" <[email protected]>
Date: 2000/11/30
Subject: Re: Modeless window act like .exe

.. cut ..
Note that this can cause some problems with modal forms shown from secondary forms. If the user switches away from the app while a modal form is up and then back to the form that showed it the modal form may hide beneath the form. It is possible to deal with this by making sure the modal form is parented to the form that showed it (using params.WndParent as above) but this is not possible with the standard dialogs from the Dialogs unit and exceptions, which need more effort to get them to work right (basically handling Application.OnActivate, looking for modal forms parented to Application via GetLastActivepopup and bringing them to the top of the Z-order via SetWindowPos).
.. cut ..

Finally here is a blog post that talks about why the changes to PopupMode and PopupParent were made.