MainFormOnTaskbar + tooltip causes focus theft

I built the code using Delphi XE2. It creates Form1, and Form1 instantly creates an instance of Form2. When I press the button on Form2, the second form 2 is created.

Now, if I hover over the button on this second, topmost, Form2 and wait for the tooltip to appear, at the moment when the tooltip appears, the first Form2 comes forward, stealing focus.

The problem only occurs if Application.MainFormOnTaskbar is True . It also relies on the first Form2 created from Form1's FormCreate method. If I use PostMessage() to delay the creation of the first Form2 until the application completes the initialization, the problem will disappear.

I would like to understand why this is happening. I already learned that the Delphi application object handles a lot of things, including the tooltip, and I know that Delphi can recreate the window handle during initialization, but I could not follow this to fully explain the behavior described above (or are these two facts even relevant).

Project1.dpr

 program Project1; uses Vcl.Forms, Unit1 in 'Unit1.pas' {Form1}, Unit2 in 'Unit2.pas' {Form2}; {$R *.res} begin Application.Initialize; Application.MainFormOnTaskbar := True; // False makes problem go away Application.CreateForm(TForm1, Form1); Application.Run; end. 

Unit1.pas

 unit Unit1; interface uses Vcl.Forms, Unit2; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); public procedure CreateForm2; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin CreateForm2; end; procedure TForm1.CreateForm2; var frm : TForm2; begin frm := TForm2.Create(Application); // (Could pass Self - makes no difference) frm.Show; end; end. 

unit2.pas

 unit Unit2; interface uses Vcl.Forms, System.Classes, Vcl.Controls, Vcl.StdCtrls, WinApi.Windows; type TForm2 = class(TForm) Button1: TButton; // This button has a hint procedure Button1Click(Sender: TObject); end; var Form2: TForm2; implementation uses System.SysUtils, Unit1; {$R *.dfm} procedure TForm2.Button1Click(Sender: TObject); begin Form1.CreateForm2; end; end. 
+4
source share
1 answer

The key issue here is that the first TForm2 instance is created as a window that belongs to the application window, Application.Handle . And here I mean the meaning of Windows owner . In VCL, this is called a pop-up parent.

Now that you create this first instance of TForm2 , the Application.MainForm property is still nil . And since you have not explicitly assigned PopupParent , the code in TCustomForm.CreateParams sets the application window for the owner.

You simply do not want your windows to belong to a hidden application window. It is for this reason that the first instance of TForm2 sometimes appears behind all other windows, especially behind your main form. It just was created with the wrong owner.

A form owned by Application.Handle is displayed in THintWindow.ActivateHint . This is due to the line that reads ParentWindow := Application.Handle . Then comes the call to SetWindowPos(Handle, ...) , which leads to the fact that the irregular shape comes to the fore. Presumably, this form goes to the front because it also belongs to Application.Handle . Right now, I don’t have a clear explanation of the exact mechanism, but I don’t find it terribly interesting, because the form is clearly configured incorrectly.

In any case, the main problem is that you created a window that does not belong correctly. Therefore, the solution is to make sure that the window belongs correctly. Do this by assigning PopupParent . For instance:

 procedure TForm1.CreateForm2; var frm : TForm2; begin frm := TForm2.Create(Application); // (Could pass Self - makes no difference) frm.PopupParent := Self; frm.Show; end; 
+6
source

All Articles