Модальные формы, скрытые формами fsStayOnTop

У меня есть форма (TBigForm в примере ниже), которая позволяет манипулировать некоторыми сложными данными и нуждается в дополнительной информации для отображения. Я поместил эту информацию в форму fsStayOnTop (в примере OnTopForm), чтобы она всегда была видимой, но при необходимости ее можно было убрать с дороги. Теперь, когда какое-то действие пользователя в TBigForm показывает модальную форму, это часто скрывается за OnTopForm, что заставляет приложение выглядеть замороженным. Как я могу избежать этого? (Поиск дает много-много хитов, но я не смог найти решение из них.)

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

Пример: создайте новое приложение VCL, перетащите TButton на форму Form1, дважды щелкните кнопку и замените созданную заглушку реализации Button1Click следующим:

type
  TBigForm = class(TForm)
  strict private
    OnTopForm: TForm;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  protected
    procedure DoHide; override;
    procedure DoShow; override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

{ TBigForm }

procedure TBigForm.Button1Click(Sender: TObject);
begin
  ShowMessage('Test');
end;

constructor TBigForm.Create(AOwner: TComponent);
begin
  inherited CreateNew(AOwner);

  Caption := 'Big form';
  WindowState := wsMaximized;

  Button1 := TButton.Create(Self);
  Button1.Parent := Self;
  Button1.Caption := 'Freeze!';
  Button1.SetBounds(10, 10, 100, 100);
  Button1.OnClick := Button1Click;
end;

procedure TBigForm.DoHide;
begin
  OnTopForm.Free;
  inherited DoHide;
end;

procedure TBigForm.DoShow;
begin
  inherited DoShow;
  OnTopForm := TForm.Create(Self);
  OnTopForm.Caption := 'Important information';
  OnTopForm.BorderStyle := bsToolWindow;
  OnTopForm.FormStyle := fsStayOnTop;
  OnTopForm.Position := poScreenCenter;
  OnTopForm.Show;
end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
  f: TBigForm;
begin
  f := TBigForm.Create(nil);
  try
    f.ShowModal;
  finally
    f.Free;
  end;
end;

Запустите приложение, нажмите "Button1", а затем "Freeze!".

(Кстати: мы используем D2007.)

4 ответа

Временно измените FormStyle вашей OnTopform перед отображением другой формы как модальной:

procedure TBigForm.Button1Click(Sender: TObject);
begin
  OnTopForm.FormStyle := fsNormal;
  ShowMessage('Test');
  OnTopForm.FormStyle := fsStayOnTop;
end;

Это должно работать на то, что вы хотите...

Попробуйте задать для свойства модальной формы PopupParent значение формы StayOnTop или установите для свойства Application.ModalPopupMode значение, отличное от pmNone, перед вызовом ShowModal().

procedure TForm1.ScreenOnActiveFormChange(Sender: TObject);
begin
  if (Screen.ActiveForm <> nil) then
  begin
    if (Screen.ActiveForm.Handle <> Application.MainForm.Handle) then
      with Screen.ActiveForm do
        SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
    Windows.SetForeGroundWindow(Screen.ActiveForm.Handle);
  end;
end;

Это должно работать.

Вот ваш вкус

Create an global TApplicationEvents
Declare an global var to keep track of modal form count
Hookup the OnMessage

var
  Ctrl: TControl;

if Msg.hwnd <> 0 then
  case Msg.message of
    CM_ACTIVATE,
    CM_DEACTIVATE:
    begin
      Ctrl := FindControl(Msg.hwnd);
      if Ctrl is TForm then
        if fsModal in TForm(Ctrl).FormState then
        begin  
          if Msg.message = CM_ACTIVATE then
            Inc(Modal form count var)
          else
            Dec(Modal form count var);

          add more logic based on Modal form count var
        end;
    end;
  end;

Повеселись

Другие вопросы по тегам