7

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

FindDialog.Execute;

FindDialog 窗口应保持在我的程序主窗口的顶部。

但是,如果我通过我自己的程序窗口从其他程序打开另一个窗口,则 FindDialog 窗口仍位于另一个窗口的顶部。

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

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


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


很有意思。我的 PrintDialog 没有保持在顶部。仍然不知道为什么我的 FindDialog 会。还在研究...


我将调用更改为: FindDialog.Execute(Handle); 还是在上面。


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


看来我不是唯一遇到这种情况的人。请参阅:Resource Tuner:版本历史,它似乎是一个 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。

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

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

4

1 回答 1

3

查看 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;


One other test could be to call NormalizeTopMosts of the Application before launching the dialog, but I know with some Delphi versions this method is broken and does not do its job.

于 2011-03-22T02:00:16.843 回答