如何在主表单中显示和/或关闭辅助表单时防止失去焦点?

时间:2010-10-07 14:15:55

标签: delphi winapi delphi-2009 vcl

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

辅助表格由主表单直接创建或通过从第二表单创建第三表单。

辅助表单在OnClose事件中设置caFree:

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

将Delphi 2009(Update 3& 4)与XP SP3一起使用。

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

  1. 创建新的VCL表单应用程序
  2. 按上述方式分配OnClose事件
  3. 将按钮拖到创建的表单
  4. 在点击处理程序中创建一个新的TForm1并将其显示如下
  5. 运行程序。单击按钮以显示第二个表单。单击第二个表单上的按钮以创建第三个表单。关闭两个新表单时,主表单将失去焦点。

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

    with TForm1.Create(Application) do
        show;
    

    有没有办法阻止我的主要表格失去焦点?

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


    过去我有the same issue这是通过更新我的delphi安装来解决的,但是在那个场景中我没有在OnClose事件中使用caFree,这是导致这个问题的原因。 错误。

    A recommendation将辅助表单上的Parent属性设置为Main Form,使新表单与主表单绑定,而我不想拥有。 (并且那里提出的解决方案总是重新激活主窗体导致表单的激活顺序丢失)

4 个答案:

答案 0 :(得分:3)

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

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

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

如果设置了MainFormOnTaskBar,拥有窗口将是我们的主要窗体,如果不是,它将是隐藏的应用程序窗口。在任何一种情况下,应用程序都将保持在前台。

关闭最后一个表单时,SetForegroundWindow调用是多余的 - 主表单,如果MainFormOnTaskBar为真,它甚至会失败,因为那时主表单不会被拥有,但我不在乎它很多(然后在调用它之前,当然还可以包括一个测试)..

答案 1 :(得分:1)

为防止主变失去焦点,您需要注释掉

// 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将保留在所有其他表单之后;所有其他形式都可以切换到前台;当主要形态关闭时,所有形式都将关闭。

答案 2 :(得分:0)

快速而肮脏的解决方案是在项目源中注释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.

答案 3 :(得分:0)

如果出现弹出式工具窗口窗体的这个问题,应用程序会在按下关闭按钮时失去焦点。

修正: OnClose事件中的 Self.Hide

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