delphi - 如何防止 FindDialog 保持在最前面 (Delphi)?

标签 delphi dialog stayontop

在Delphi 2009中,我做了一个简单的:

FindDialog.Execute;

FindDialog 窗口按其应有的方式保留在程序主窗口的顶部。

但是,如果我在自己的程序窗口上从其他程序打开另一个窗口,FindDialog 窗口将保留在另一个窗口的顶部。

如果我使用另一个程序(例如记事本)中的 FindDialog 尝试此操作,则不会发生这种情况。在记事本及其 FindDialog 上打开另一个程序的窗口将同时覆盖记事本和 FindDialog 窗口。这似乎是正确且预期的行为。

这是我做错了什么还是Delphi实现FindDialog的方式有问题?我可以做些什么来让它以记事本的方式工作吗?

<小时/>

谢谢大家的评论。您无法重现我的问题这一事实已经表明这是其他原因造成的。这将帮助我追踪它。当我发现一些东西时,我会进行更多研究并在此处发布更多信息。

<小时/>

非常有趣。我的 PrintDialog 没有保持在顶部。仍然不知道为什么我的 FindDialog 会这样做。还在研究中...

<小时/>

我将调用更改为:FindDialog.Execute(Handle);仍然位居榜首。

<小时/>

我在主窗体中添加了另一个 FindDialog(这次是 FindDialog1),并在程序启动时执行它。它具有相同的保持领先行为。这至少表明它与我的 FindDialog 或我与之相关的自定义无关。所以它一定是我主窗体中的一个设置。

<小时/>

看来我不是唯一遇到这种情况的人。请参阅:Resource Tuner: Version History它似乎是一个 Delphi 应用程序,在版本 1.99 下它指出:“错误修复:切换到另一个应用程序时,(搜索)对话框预览窗口保持在顶部。”我可能会尝试联系他们,看看他们是否记得他们的解决方案是什么。

<小时/>

我向表单添加了一些新对话框,并将这些调用放在一个位置:

FindDialog1.Execute();
PrintDialog1.Execute();
ReplaceDialog1.Execute();
FontDialog1.Execute();

FindDialog 和 ReplaceDialog 位于其他窗口前面的顶部。 PrintDialog 和 FontDialog 没有保持在顶部并按其应有的方式工作。

那么两组对话框之间有什么不同导致前两组对话框出错?

<小时/>

此外,这个问题发生在我用 Delphi 4 编译的旧版本程序中。 哎呀。现在我发现这个问题在我使用Delphi 4的旧版本中没有发生。

并且是一位用户报告了这个问题。他使用Windows XP,而我在Vista 上开发,所以它发生在不同的操作系统下。

<小时/>

确认:是的,我创建了一个新表单并在其上添加了一个 FindDialog。 FindDialog 没有这个问题。这表明我的程序中的某些内容导致 FindDialog 保持在顶部。现在,我必须找出那是什么。还有更多想法吗?如果有人给我一个答案,甚至给我一个线索来帮助我解决这个问题,那么他们就会得到被接受的答案。

<小时/>

解决方案:Sertac 对答案的编辑给了我解决方法:

  Application.NormalizeTopMosts;
  FindDialog.Execute();
  Application.RestoreTopMosts;

这样做可以防止当应用程序不是 TopMost 时 FindDialog 成为 TopMost。

...但我仍然真的不明白这一点(Delphi 关于 NormalizeTopMosts 的帮助)非常令人困惑,并且并不表明它应该这样做。

希望这个“修复”不会导致其他问题。

最佳答案

查看 VCL 代码,查找对话框保持在顶部的唯一可能方式是,当调用“执行”时已经有一个最顶部的窗口。这就是它的编码方式,对话框由“TRedirectorWindow”拥有,而“TRedirectorWindow”由应用程序中 z 顺序的顶部窗口拥有。如果此“顶部窗口”是最顶部窗口,则查找对话框也是最顶部窗口。

procedure TForm1.Button1Click(Sender: TObject);
var
  f: TForm;
begin
  f := TForm.CreateNew(Self);
  f.FormStyle := fsStayOnTop;
  f.Show;
  FindDialog1.Execute;
end;

或者,

procedure TForm1.Button1Click(Sender: TObject);
begin
  FormStyle := fsStayOnTop;
  FindDialog1.Execute;
  FormStyle := fsNormal;
end;


以上示例将创建一个最顶层的查找对话框。但是留在顶部的表单可能不会被忽视,所以我想这不会是您问题的根源。

无论如何,要么是这样,要么您通过其他代码片段以某种方式更改了对话框上的样式。


顺便说一句,不要费心测试将各种句柄传递给 FindDialog1.Execute(),它不会有效果,请参阅我对您的问题的评论。

编辑:

这个怎么样:

procedure TForm1.Button4Click(Sender: TObject);
var
  f: TForm;
begin
  f := TForm.CreateNew(Self);
  f.FormStyle := fsStayOnTop;
  f.Show;
  f.Hide;
  FindDialog1.Execute;
end;

重点是,窗口不必可见即可被 EnumThreadWindows 枚举。 。因此,任何现有的置顶表单都可能导致查找对话框表现出此行为。

测试和观察比猜测更好。在启动查找对话框之前运行以下测试。这结合了“dialogs.pas”执行的逻辑来查找对话框的基础,并且如果对话框位于最顶层,则会引发异常。

function EnumThreadWndProc(hwnd: HWND; var lParam: LPARAM): Bool; stdcall;
var
  Window: TWinControl;
begin
  Result := True;
  Window := FindControl(hwnd);
  if Assigned(Window) and (Window is TForm) then begin
    Result := False;
    lParam := Longint(Window);
  end;
end;

procedure TForm1.Button6Click(Sender: TObject);
var
  OnTopForm: Longint;
begin
  OnTopForm := 0;
  EnumThreadWindows(GetCurrentThreadId, @EnumThreadWndProc, LPARAM(@OnTopForm));
//  if (OnTopForm <> 0) and (TForm(OnTopForm).FormStyle = fsStayOnTop) then
  if (OnTopForm <> 0) and (GetWindowLong(TForm(OnTopForm).Handle,
                            GWL_EXSTYLE) and WS_EX_TOPMOST = WS_EX_TOPMOST) then
    raise Exception.Create('darn! got one: ' + TForm(OnTopForm).Name);
end;


另一个测试可能是在启动对话框之前调用应用程序的 NormalizeTopMosts,但我知道在某些 Delphi 版本中,此方法已损坏并且无法完成其工作。

关于delphi - 如何防止 FindDialog 保持在最前面 (Delphi)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5373946/

相关文章:

java - 如何在不使用任何 "ButtonType"控件的情况下在 JavaFx 中创建自定义对话框?

java - 单击图像时不出现对话框 fragment

delphi - 如何在其所有者表单之上显示模态表单(其所有者是否设置为 fsStayOnTop),就像 TOpenDialog 一样

PHP 函数到 Delphi 函数

delphi - 如何内部处理过滤后的 tDataSet 记录,使其不显示在 tDBGrid 结果上

java - 在 Android 搜索对话框中获取按钮

delphi - "Stay on top"Delphi XE中的主窗体和模式对话框

windows - 什么外部事件触发 TCustomForm.RecreateWnd?

delphi - 如何在Delphi程序本身中插入图片?