从主窗体显示和/或关闭辅助窗体时如何防止失去焦点?

发布于 2024-09-26 16:06:57 字数 1092 浏览 9 评论 0原文

显示主窗体中的 2 个辅助窗体,然后关闭这两个窗体将导致主窗体失去焦点。 (另一个应用程序被激活,而不是我的)

辅助表单可以由主表单直接创建,也可以通过从第二个表单创建第三个表单来创建。

辅助窗体在 OnClose 事件中设置 caFree:

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

使用 Delphi 2009(更新 3 和 4)与 XP SP3。

以下是我重现该问题的步骤:

  1. 创建一个新的 VCL 表单应用程序
  2. 如上所述分配 OnClose 事件
  3. 将一个按钮拖动到创建的表单上
  4. 在单击处理程序中创建一个新的 TForm1 并将其显示如下

运行程序。单击该按钮显示第二个表单。单击第二个表单上的按钮创建第三个表单。关闭两个新表单时,主表单将失去焦点。

这是我在按钮单击事件处理程序中的代码:

with TForm1.Create(Application) do
    show;

有什么方法可以阻止我的主窗体失去焦点吗?

(有趣的是,当直接从主表单创建两个辅助表单时,只有在关闭第一个创建的表单然后关闭第二个创建的表单时才会出现该问题)


过去我有 同样的问题通过更新我的delphi安装解决了,但在那种情况下我没有不要在 OnClose 事件中使用 caFree,这是造成此问题的原因 漏洞。

建议将辅助窗体上的 Parent 属性设置为主窗体,使得新表单绑定到我不想拥有的主表单。 (并且那里提出的始终重新激活主表单的解决方案会导致表单的激活顺序丢失)

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

宁愿没拥抱 2024-10-03 16:06:57

我会在其中一个表单关闭之前使用 api 调用手动激活“拥有”窗口:

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

这不会是操作系统的问题(即没有闪烁的任务栏按钮),因为我们的应用程序已经在前台。

如果设置了MainFormOnTaskBar,则拥有的窗口将是我们的主窗体,否则它将是隐藏的应用程序窗口。无论哪种情况,应用程序都将保留在前台。

关闭最后一个窗体(主窗体)时,SetForegroundWindow 调用是多余的,如果 MainFormOnTaskBar 为 true,它甚至会失败,因为那时主窗体将不被拥有,但我不会不太关心(当然,当然可以在调用之前包含一个测试)..

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)..

萌化 2024-10-03 16:06:57

为了防止主窗体失去焦点,您需要注释掉

// Application.MainFormOnTaskBar := True;

@Serg 已经建议的内容。正如您已经注意到的,这样做的缺点是辅助表单可以位于主表单后面。通过将表单的 PopupMode 设置为 pmAuto 可以轻松防止这种情况,这可确保由表单创建的表单将保留在创建它们的表单之上。

但是,这也确保了从辅助表单创建的表单在创建它们的表单关闭时也将关闭。例如:

  • MainForm 创建Secondary1
  • secondary1 创建Secondary2 和Secondary3

关闭Secondary1 也将关闭Secondary2 和Secondary3。

如果这是不需要的行为,您可以通过显式设置 PopupParent 来断言更多控制。例如,将所有表单作为应用程序主表单的“父级”:

procedure TForm1.FormCreate(Sender: TObject);
begin
  PopupMode := pmAuto;
  if Self <> Application.MainForm then
    PopupParent := Application.MainForm;
end;

这可确保 Application.MainForm 将保留在所有其他表单后面;所有其他形式都可以切换到前台;当主窗体关闭时,所有窗体都会关闭。

To prevent the mainform losing focus, you need to comment out the

// Application.MainFormOnTaskBar := True;

as @Serg already suggested. The drawback of this, as you already noticed, is that the secondary forms can go behind the mainform. This is easily prevented by setting the form's PopupMode to pmAuto, which ensure that forms created by a form will stay on top of the form from which they were created.

However, this also ensures that forms created from a secondary form will be closed when the form that created them is closed. For example:

  • MainForm creates Secondary1
  • Secondary1 creates Secondary2 and Secondary3

Closing Secondary1 will close Secondary2 and Secondary3 as well.

If that is unwanted behaviour, you can assert more control by setting the PopupParent explicitely. For example to "parent" all forms to the application's main form:

procedure TForm1.FormCreate(Sender: TObject);
begin
  PopupMode := pmAuto;
  if Self <> Application.MainForm then
    PopupParent := Application.MainForm;
end;

This ensures that the Application.MainForm will remain behind all other forms; all other forms can switch to the foreground; and all forms will close when the mainform is closed.

七度光 2024-10-03 16:06:57

一个快速而肮脏的解决方案是在项目源代码中注释 MainFormOnTaskbar 行:

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
//  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

已更新

如果您希望 MainForm 始终位于其他表单后面,您还应该覆盖 CreateParams。以下代码按您的预期工作,尽管我怀疑它可能因其他原因而无法使用:

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  with TForm1.Create(Application) do
    show;
end;

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  if Application.MainForm <> nil
    then Params.WndParent:= Application.MainForm.Handle
    else Params.WndParent:= 0;
end;

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

end.

A quick and dirty solution is to comment MainFormOnTaskbar line in the project source:

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
//  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

Updated

If you want the MainForm to be always behind the other forms you should also override CreateParams. The following code works as you expect, though I suspect it may appear unusable for some other reason:

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  with TForm1.Create(Application) do
    show;
end;

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  if Application.MainForm <> nil
    then Params.WndParent:= Application.MainForm.Handle
    else Params.WndParent:= 0;
end;

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

end.
涫野音 2024-10-03 16:06:57

弹出工具窗口表单存在此问题,按下关闭按钮时应用程序将失去焦点。

使固定:
OnClose 事件中的Self.Hide

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

Had this issue for a popup Toolwindow form, application would loose focus when close button was pressed.

Fix:
Self.Hide in the OnClose event.

procedure TPopupForm.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  Self.Hide;
  Action := caFree;
end;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文