2010-08-04 96 views
2

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

在我的真实应用程序中有很多显示模式窗体的地方,所以我想避免更改所有这些电话。

:创建一个新的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; 

启动应用程序,点击“按钮1“,然后在”冻结!“。

(BTW:我们使用D2007)显示另一种形式,模式

+0

这很有趣 - 在3.5年后,一片茫然,没有任何评论。 – 2014-02-06 17:16:45

+0

这是一个upvote抵消downvote。 – Shannon 2014-12-07 04:31:08

+0

@Shannon,谢谢! :-) – 2014-12-07 09:24:52

回答

1

更改您的OnTopform暂时的FormStyle前:

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

应该为你想要的工作...

+0

谢谢!这似乎工作,但它需要操纵ShowModal,ShowMessage等每个调用 - 我想避免这种情况。使用Application.OnModalBegin在这里没有帮助,因为如果嵌套ShowModal调用,它只会被调用一次。 :-( – 2010-08-04 19:26:47

2

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

+0

前者会更改应用程序的窗口层次结构 - StayOnTop窗体将保留在模态窗体下,而后者也无济于事,因为'ShowMessage'是从模态窗体调用的,但StayOnTop窗体是不同的形式,它仍然会保持在顶端 – 2010-08-05 23:15:55

+0

你可以两种方式,你说问题是模式窗口滞留在StayOnTop窗口后面,所以显然模态窗口需要显示在顶部。 ,只需在调用ShowModal()之前将模式窗口移动到StayOnTop窗口之外的区域,对于ShowMessage(),它将显示一个模态TForm,并且受此TApplication.ModalPopupMode属性的约束 – 2010-08-05 23:58:33

+0

正如我所看到的,问题不在于StayOnTop表单中卡住的模式表单,而是ShowMessage表单在StayOnTop表单下卡住了,并且由于ShowMessage是从Modal表单调用的nd **不是从StayOnTop表单获得的,它将不会被StayOnTop表单所有..使用任何ModalPopupMode ... – 2010-08-06 00:47:15

0

这里您伪善

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; 

玩得开心

+0

我无法获取Inc/Dec行被调用 - Ctrl始终为零。你在我的示例应用程序中尝试过吗? – 2010-08-05 09:11:12

0
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; 

这应该工作。