16

在 Windows 98 时代之后,我们多次经历过一些对话框失去了它们的 Z-Order 并返回到以前的形式。

例如:

Dialog1.ShowModal;

Dialog1.OnClickButton() : ShowMessage('anything');

当MessageBox 出现时,它有时没有焦点,被移到Dialog1 下。用户对此感到困惑,他们说:我的应用程序冻结了!!!但如果他们使用 Alt+Tab 移动到另一个应用程序并返回,焦点将返回到 MessageBox,它将成为前台窗口。

我们在 ShowMessage、MessageBox、普通表单和 QuickReport 表单中都经历过这种情况。

有人知道吗?它是Windows错误吗?你怎么能防止它?如何抓住这个?

感谢您的帮助:dd


我真的说过,在Win98之后,所以所有的操作系​​统(Win7也是)都受到这个问题的影响。我们使用了 Delphi 6 Prof,因此这些属性不适用于默认表单。

有人说消息对话框可以用 MessageBox + MB_APPLMODAL 控制。这是个好消息,但我们有许多旧的表单和组件、第三方工具。

因此,通过表格替换来制作一个全新的应用程序是一项艰巨的工作。

但我们会尝试这样做。

我认为答案是一半是应用程序问题,一半是 Windows 问题。如果 Windows 有时会处理这个问题,有时不会 - 这似乎是一个 Windows 错误。但是如果我们可以强制制作好的模态窗口,那么它就是一个编程错误。

有人可以向我解释 WS_POPUP 标志的含义是什么吗?它有没有副作用?

谢谢:dd

4

4 回答 4

16

这就是PopupModeandPopupParent属性的用途。

例如,你可以这样做:

Dialog1.PopupMode := pmExplicit;
Dialog1.PopupParent := self;
Dialog1.ShowModal;

这告诉 Windows 正确的 Z 顺序。

于 2010-06-08T13:09:23.887 回答
7

对于旧版本的 delphi(Delphi 2007 之前),在主窗体以外的窗体上:

interface
  TMyForm = Class(TForm)
  protected
    procedure CreateParams(var Para: TCreateParams); override;
  end;
...
implementation
...
procedure TMyForm.CreateParams(var Para: TCreateParams);
begin
  inherited;
  Para.Style := Para.Style or WS_POPUP;
  { WinXP Window manager requires this for proper Z-Ordering }
  // Para.WndParent:=GetActiveWindow;
  Para.WndParent := Application.MainForm.Handle;
end;

对于消息框,在您的标志中包含 MB_TOPMOST:

Application.MessageBox(PChar(amessage), PChar(atitle),    otherflags or MB_TOPMOST);
于 2010-06-08T17:29:14.470 回答
0

我看了半个小时这个页面和常见问题解答,仍然找不到如何发表评论,所以请原谅我这种违反协议的行为。

首先,我想明确指出,恕我直言,张贴者没有使用 Windows 98。他写道“在 Windows 98 时代之后”,我理解这意味着他在 98 之后的 Windows 版本中遇到了这个问题。

由于我也遇到了这个问题(CB2009),我想强调发帖者的问题“它是 Windows 错误吗?”,我还没有看到答案。如果它是 Delphi/Builder 错误,也许有办法避免它?我看不出拦截所有潜在对话如何是可行的解决方案,也无法避免使用 fsStayOnTop。我有一个设置表单需要保留在我的主表单之上,但是设置表单可以并且将会弹出对话框,在某些条件下会在设置表单下消失。

如果我能理解 z-order 的支持在哪里出错,那将非常有帮助,因为它可能会为如何避免它提供线索。

于 2010-06-09T10:49:45.200 回答
0

我最近使用的一个技巧是在创建每个表单的过程中应用这两行代码:

SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or 
  WS_EX_APPWINDOW or WS_EX_TOPMOST);
SetWindowLong(Handle, GWL_HWNDPARENT, GetDesktopWindow);

Handle 是表单的句柄(Form1.Handle)。WS_EX_APPWINDOW 部分使每个窗口都出现在任务栏上,如果您不想要那种额外的效果,请将其删除。

对于我的主要形式,我使用这一行:

SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or
  WS_EX_TOPMOST);

我还使用这个函数来帮助构建我的自定义对话框(我为每种样式的对话框创建了一个新函数 - 错误、确认等):

function CustomDlg(const AMessage : string; const ADlgType: TMsgDlgType;
  const AButtons: TMsgDlgButtons; const ADefaultButton: TMsgDlgBtn) : TForm;
begin
  Result := CreateMessageDialog(AMessage, ADlgType, AButtons, ADefaultButton);
  with Result do
    begin
      SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or 
        WS_EX_APPWINDOW or WS_EX_TOPMOST);
      SetWindowLong(Handle, GWL_HWNDPARENT, GetDesktopwindow);
      FormStyle := fsStayOnTop;
      BringToFront;
    end;
end;

当然,这FormStyle := fsStayOnTop;部分是可选的,但我使用它来确保我的确认和错误对话框始终对用户可见。

这似乎有点工作,但最终效果是我不再需要担心表单会意外隐藏在其他表单后面。

于 2011-08-31T11:24:27.810 回答