30

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

编辑

我使用德尔福 7。

4

6 回答 6

26

你没有提到哪个版本的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,正如我所展示的那样,如果模态表单中出现问题,则始终会重新启用创建表单。

于 2009-10-28T19:02:19.433 回答
8

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

于 2009-11-19T19:37:07.757 回答
2

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

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

我能看到的唯一问题是,它会导致允许用户最小化、移动或关闭没有响应的应用程序的主窗口的功能出现问题。但是通过这种方式,您不必用Self.Enabled := False代码覆盖每个调用。

于 2009-11-18T19:07:33.573 回答
1

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

于 2010-10-20T09:40:21.267 回答
0

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

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

于 2009-10-28T18:50:13.120 回答
0

试试 OnShowForm:

PostMessage(Self.Handle, WM_USER_SET_FOCUS_AT_START, 0, 0);
于 2015-07-08T06:45:55.903 回答