Как предотвратить потерю фокуса при показе и / или закрытии вторичных форм из основной формы? - PullRequest
3 голосов
/ 07 октября 2010

Отображение 2 вторичных форм из основной формы и затем закрытие обеих форм приведет к тому, что основная форма потеряет фокус.(другое приложение активируется вместо моего)

Вторичные формы создаются либо основной формой напрямую, либо путем создания третьей формы из второй формы.

Вторичные формы устанавливают caFree вСобытие OnClose:

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;

Есть ли способ, чтобы моя основная форма не потерялаfocus?

(Интересно, что при создании обеих вторичных форм непосредственно из главной формы проблема возникает только при закрытии первой созданной формы, а затем второй созданной формы)


ВВ прошлом у меня была та же проблема , которая была решена путем обновления моей установки delphi, но в этом сценарии я не использовал caFree в событии OnClose, которое является причиной этой ошибки.

Рекомендация о том, чтобы установить для свойства Parent на вторичных формах значение Main Form, новые формы будут привязаны к основной форме, которую я бы предпочел не иметь.(и решение, предложенное здесь для постоянной повторной активации основной формы, приводит к потере порядка активации форм)

Ответы [ 4 ]

3 голосов
/ 03 января 2012

Я бы вручную активировал окно-владелец вызовом API перед закрытием одной из форм:

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

Это не будет проблемой для ОС (т. Е. Нет мигающей кнопки панели задач), потому что наше приложение уже находится на переднем плане.

Если установлено значение MainFormOnTaskBar, окно-владелец будет нашей основной формой, в противном случае это будет скрытое окно приложения. В любом случае приложение останется на переднем плане.

Вызов SetForegroundWindow является избыточным при закрытии последней формы - основной формы, он даже потерпит неудачу, если MainFormOnTaskBar истинно, так как тогда основная форма не будет принадлежать, но мне было бы все равно опять же, можно, конечно, включить тест перед его вызовом) ..

1 голос
/ 07 октября 2010

Чтобы предотвратить потерю фокуса основной формой, необходимо закомментировать

// 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 останется позади всех других форм; все остальные формы могут переключаться на передний план; и все формы закроются, когда основная форма закроется.

0 голосов
/ 19 марта 2013

Если бы эта проблема возникла для всплывающей формы окна инструментов, приложение теряло бы фокус при нажатии кнопки закрытия.

Исправлена ​​ошибка: Self.Hide в событии OnClose.

procedure TPopupForm.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  Self.Hide;
  Action := caFree;
end;
0 голосов
/ 07 октября 2010

Быстрое и грязное решение - прокомментировать строку 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.
...