2009-10-28 123 views
19

我的应用程序基于模态窗体。主窗体用ShowModal打开一个窗体,这个窗体用ShowModal打开另一个窗体,所以我们堆叠了模态窗体。有时会出现一个问题,当我们以新形式调用ShowModal时,它隐藏在以前的表单之后,而不是显示在顶部。按alt + tab后,窗体回到顶部,但这不是一个好的解决方案。你遇到了这个问题,你是如何处理它的?当调用ShowModal时,窗体隐藏在其他窗体的后面

编辑

我用Delphi 7

+0

感谢添加的版本。如果你在问题的文字或标签中加入了它,它会有所帮助。 :-) – 2009-10-28 19:07:03

+0

我没有设置适当的标签,然后添加编辑:) – LukLed 2009-10-28 19:08:46

+0

只要你把它放在什么地方,它就可以。它不一定必须位于其中一个标签中,只要它位于某个问题的主题或文本中即可。这可以让人们在回答时知道你有什么功能。 :-) – 2009-10-28 19:33:26

回答

20

你没有提到的Delphi的版本...

较新版本的Delphi增加了两个新的属性,以TCustomForm:PopupMode和PopupParent。将模态对话框的PopupParent设置为创建该对话框的窗体可确保子窗体保持在其父窗体之上。它通常可以解决你所描述的问题。

我认为这对属性是在2006年德尔福中添加的,但可能是2005年。它们绝对存在于Delphi 2007及更高版本中。

编辑:在看到您使用Delphi 7后,我唯一的建议是,在显示您的模式窗体的代码中,禁用创建它的窗体并在返回时重新启用。这应该防止创建窗口接收输入,这可能有助于保持Z顺序正确。

像这样的东西可能工作(未经测试,因为我不再使用D7):

procedure TForm1.ShowForm2; 
begin 
    Self.Enabled := False; 
    try 
    with TForm2.Create(nil) do 
    begin 
     try 
     if ShowModal = mrOk then 
      // Returned OK. Do something; 
     finally 
     Free; 
     end; 
    end; 
    finally 
    Self.Enabled := True; 
    end; 
end; 

如果窗体2创建了一个模态窗口(如你所提到的),只是重复这个过程 - 禁用窗体2 ,创建Form3并以模态方式显示它,并在返回时重新启用Form2。请确保按照我所示的方式使用try..finally,以便在模态窗体中出现错误时始终重新启用创建窗体。

+0

对不起,这是Delphi 7.没有PopupMode和PopupParent,但知道它们存在是很好的。 – LukLed 2009-10-28 19:04:32

+0

我可以试试这个解决方案,但是我们在项目中有很多模态表单,消息框是模态的,所以它可能有时很难实现。但我会尽可能地做到这一点。 – LukLed 2009-10-28 21:06:14

+0

它为我使用Self.Enabled:= False;和Self.Enabled:= True; – 2013-04-10 09:27:26

-1

我发现,使用“总在最前面”标志上不止一种形式导致与Z顺序问题。你也可能发现需要BringWindowToTop功能。

使用内置的WinAPI(MessageBox)启动消息框时,我发现必须传递调用窗口的句柄以确保提示始终显示在最前面。

+1

查看我对Lars D.所有者(或父母)的回复与所描述的问题无关。这个问题是TAppication隐藏窗口从任务栏中移除的后果;它引起了儿童表格在Z顺序中失去适当位置的问题,这就是PopupParent和PopupMode被创建来解决的问题。 – 2009-10-28 19:05:44

+0

不够公平......在进一步检查时,我意识到我在考虑使用Windows.MessageBox函数并传递调用窗口的句柄,以确保MessageBox显示在调用者的顶部 - 我正在考虑的是“父母”。将编辑我的答案来反映这一点。 – 2009-10-28 21:37:39

2

从这个link看来,问题出现在2000/XP中引入的“重影窗口”。您可以通过在启动时调用以下代码来禁用重影功能。

procedure DisableProcessWindowsGhosting; 
var 
    DisableProcessWindowsGhostingProc: procedure; 
begin 
    DisableProcessWindowsGhostingProc := GetProcAddress(
    GetModuleHandle('user32.dll'), 
    'DisableProcessWindowsGhosting'); 
    if Assigned(DisableProcessWindowsGhostingProc) then 
    DisableProcessWindowsGhostingProc; 
end; 

,我可以看到的唯一问题是,它会导致与允许用户minimize, move, or close the main window of an application that is not responding的功能问题。但通过这种方式,您不必使用Self.Enabled := False代码覆盖每个呼叫。

+0

如果真的有效,那会很好。谢谢。这个问题困扰了我很长一段时间。然而,如果表单具有WS_POPUP风格并且“所有者”是正确的窗口,那么即使是“幻影”形式也不允许将Z-order切换到它的所有者之下,因此没有机会一个突然消失的模态对话框。“我没有看到任何表单中的所有者参考。 – LukLed 2009-11-18 19:28:45

4

对不起,添加了一个单独的答案,但我做了一些更多的研究,其中一些表明我以前的答案(DisableProcessWindowsGhosting)没有帮助。由于我不能总是重现这个问题,我不能肯定地说。

我找到了合适的解决方案。我在Delphi 2007中引用了CreateParams方法中的代码,并且它非常接近(没有处理PopupMode的所有其他代码)。

我创建了下面的单元TForm

unit uModalForms; 

interface 

uses Forms, Controls, Windows; 
type 
    TModalForm = class(TForm) 
    protected 
    procedure CreateParams(var params: TCreateParams); override; 
    end; 

implementation 

procedure TModalForm.CreateParams(var params: TCreateParams); 
begin 
    inherited; 

    params.WndParent := Screen.ActiveForm.Handle; 

    if (params.WndParent <> 0) and (IsIconic(params.WndParent) 
    or not IsWindowVisible(params.WndParent) 
    or not IsWindowEnabled(params.WndParent)) then 
    params.WndParent := 0; 

    if params.WndParent = 0 then 
    params.WndParent := Application.Handle; 
end; 

我要做的则是包括本机与形式的单元,然后更改从class(TForm)窗体类(在.PAS代码文件)class(TModalForm)

它的工作对我来说,似乎接近CodeGear的解决方案。

+0

我会先尝试使用DisableProcessWindowsGhosting并检查它是否可用。然后我会看看这个。谢谢。 – LukLed 2009-11-24 00:51:56

+0

完美地工作 - 感谢吉姆 – tomo7 2013-11-17 11:07:25

1

只需设置形式的Visible财产,要开模,到False。然后你可以打开它.ShowModal();它会工作。

0

尝试 OnShowForm:

+1

6年太晚了,但谢谢:) – LukLed 2015-07-08 08:45:23

相关问题