调用ShowModal时,表单隐藏在其他表单后面

时间:2009-10-28 18:20:15

标签: delphi delphi-7

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

修改

我使用Delphi 7。

6 个答案:

答案 0 :(得分:23)

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

较新的Delphi版本为TCustomForm添加了两个新属性:PopupMode和PopupParent。将模式对话框的PopupParent设置为创建该对话框的表单,确保子表单保留在其父对象的顶部。它通常可以解决您所描述的问题。

我认为这两个属性是在Delphi 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;

如果Form2创建了一个模态窗口(正如您所提到的),只需重复该过程 - 禁用Form2,创建Form3并以模态方式显示它,并在返回时重新启用Form2。确保使用try..finally,如我所示,这样如果模态形式出现问题,创建表单将始终重新启用。

答案 1 :(得分:6)

很抱歉添加一个单独的答案,但我做了一些研究,其中一些表明我之前的答案(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;

我所做的是将此单元包含在表单单元中,然后将表单的类(在.pas代码文件中)从class(TForm)更改为class(TModalForm)

它对我有用,似乎接近CodeGear的解决方案。

答案 2 :(得分:2)

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

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代码覆盖每个来电。

答案 3 :(得分:1)

只需将要打开模式的表单的 Visible 属性设置为 False 。然后,您可以使用 .ShowModal(); 打开它,它会起作用。

答案 4 :(得分:0)

试试吧 OnShowForm:

PostMessage(Self.Handle, WM_USER_SET_FOCUS_AT_START, 0, 0);

答案 5 :(得分:-1)

我发现在多个表单上使用“Always On Top”标志会导致Z顺序出现问题。您可能还需要BringWindowToTop函数。

使用内置的WinAPI(MessageBox)启动消息框时,我发现传递调用窗口的句柄是必要的,以确保提示始终显示在顶部。 / p>