【问题标题】:Modal forms hidden by fsStayOnTop formsfsStayOnTop 表单隐藏的模态表单
【发布时间】:2010-08-04 18:29:40
【问题描述】:

我有一个表单(在下面的示例中为 TBigForm),它允许操作一些复杂的数据并需要显示额外的信息。我将此信息放在 fsStayOnTop 表单(示例中为 OnTopForm)中,以确保它始终可见,但如有必要可以将其移开。现在,当 TBigForm 中的某些用户操作显示模态表单时,这通常会隐藏在 OnTopForm 后面,这会使应用程序看起来冻结。我怎样才能避免这种情况? (搜索产生了很多很多的点击,但我无法从中提炼出解决方案。)

在我的真实应用中,有很多地方会显示模态表单,所以我想避免更改所有这些调用。

示例:创建一个新的 VCL 应用程序,在 Form1 上放置一个 TButton,双击该按钮并将生成的 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。)

【问题讨论】:

  • 这很有趣 - 3.5 年后凭空投反对票,没有任何评论。
  • 这是一个反对反对票的赞成票。
  • @Shannon,谢谢! :-)
  • xe5的解决方法是什么?

标签: delphi modal-dialog stayontop


【解决方案1】:

在将另一个表单显示为模态之前暂时更改 OnTopform 的 FormStyle:

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

它应该适合你想要的......

【讨论】:

  • 谢谢!这似乎可行,但它需要操纵对 ShowModal、ShowMessage 等的每一次调用。我想避免这种情况。在这里使用 Application.OnModalBegin 没有帮助,因为如果您嵌套 ShowModal 调用,它只会被调用一次。 :-(
【解决方案2】:

在调用 ShowModal() 之前,尝试将模态窗体的 PopupParent 属性设置为 StayOnTop 窗体,或将 Application.ModalPopupMode 属性设置为 pmNone 以外的值。

【讨论】:

  • 前者会改变应用程序的窗口层次结构——StayOnTop 表单将保留在模态表单下。后者也无济于事,因为“ShowMessage”是从模态表单调用的,但 StayOnTop 表单是不同的表单,它仍将保持在顶部。
  • 你不能同时拥有它。你说问题是模式窗口卡在了 StayOnTop 窗口后面。所以很明显,模态窗口需要显示在它上面。否则,只需在调用 ShowModal() 之前将模式窗口移动到 StayOnTop 窗口之外的区域。至于 ShowMessage(),它显示一个模态 TForm,因此受制于 TApplication.ModalPopupMode 属性。
  • 在我看来,问题不是模态表单卡在 StayOnTop 表单下,而是 ShowMessage 表单卡在 StayOnTop 表单下。并且由于 ShowMessage 是从 Modal 表单调用的,而 不是 从 StayOnTop 表单调用的,因此它不会被 StayOnTop 表单拥有。任何 ModalPopupMode...
【解决方案3】:

这是你的好东西

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;

玩得开心

【讨论】:

  • 我无法调用 Inc/Dec 行 - Ctrl 始终为零。您在我的示例应用中尝试过吗?
【解决方案4】:
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;

这应该可行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-13
    • 1970-01-01
    • 2022-01-21
    • 2011-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多