简体   繁体   English

如何让FindDialog保持最佳状态(Delphi)?

[英]How Can I Keep the FindDialog from Staying on Top (Delphi)?

In Delphi 2009, I do a simple: 在Delphi 2009中,我做了一个简单的事情:

FindDialog.Execute;

The FindDialog window stays on top of my program's main window as it should. FindDialog窗口保持在程序主窗口的顶部。

However, if I open another window from some other program over my own program's window, the FindDialog window remains on top of the other window. 但是,如果我在我自己的程序窗口中打开来自其他程序的另一个窗口,则FindDialog窗口仍然位于另一个窗口的顶部。

If I try this with a FindDialog from another program (eg Notepad), this does not happen. 如果我尝试使用其他程序(例如记事本)的FindDialog,则不会发生这种情况。 Opening another program's window over Notepad and its FindDialog will cover both the Notepad and FindDialog windows. 在记事本和其FindDialog上打开另一个程序窗口将覆盖Notepad和FindDialog窗口。 This seems to be the correct and expected behavior. 这似乎是正确和预期的行为。

Is this something I'm doing wrong or is this a problem with the way Delphi has implemented the FindDialog? 这是我做错了还是Delphi实现FindDialog的问题? Is there something I can do to make it work the Notepad way? 有什么我可以做到使记事本的方式工作?


Thank you all for the comments. 谢谢大家的评论。 The fact that you cannot reproduce my problem is already a clue that it is something else causing this. 您无法重现我的问题的事实已经是一个线索,它是导致这种情况的其他原因。 This will help me track it down. 这将有助于我追踪它。 I'll research a little more and post additional info here when I find out something. 当我发现一些东西时,我会再研究一下并发布更多信息。


Very interesting. 很有意思。 My PrintDialog doesn't stay on top. 我的PrintDialog不会保持领先。 Still don't know why my FindDialog does. 仍然不知道为什么我的FindDialog会这样做。 Still researching... 还在研究......


I changed the call to: FindDialog.Execute(Handle); 我将调用更改为:FindDialog.Execute(Handle); Still on top. 还是排在最前面。


I added another FindDialog (this time FindDialog1) to my main form and I execute it at startup of my program. 我在我的主窗体中添加了另一个FindDialog(这次是FindDialog1),并在程序启动时执行它。 It has the same stay-on-top behavior. 它具有相同的保持最佳行为。 That at least indicates it wasn't anything to do with my FindDialog or customizations I made to do with it. 这至少表明它与我的FindDialog或我用它做的自定义没有任何关系。 So it must be a setting in my main form. 所以它必须是我主要形式的设置。


It doesn't look like I'm the only one who's encountered this. 看起来我不是唯一一个遇到过这种情况的人。 See: Resource Tuner: Version History which appears to be a Delphi application, where under Version 1.99 it states: "Bugfix: The (search) dialog preview window stayed on top when switching to another application." 请参阅: 资源调优器:版本历史似乎是一个Delphi应用程序,在版本1.99下它指出:“修正:切换到另一个应用程序时,(搜索)对话框预览窗口保持在顶部。” I might try contacting them and see if they might remember what their fix was. 我可能会尝试联系他们,看看他们是否记得他们的修复方法。


I add some new dialogs to my form and put these calls in one place: 我在表单中添加了一些新的对话框,并将这些调用放在一个地方:

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

The FindDialog and ReplaceDialog stay on top in front of other windows. FindDialog和ReplaceDialog保持在其他窗口的顶部。 The PrintDialog and FontDialog do not stay on top and work as they should. PrintDialog和FontDialog不会保持最佳状态并且可以正常工作。

So what is different between the two sets of dialogs that make the first two do it wrong? 那么两组对话框之间的区别是什么让前两个对话框出错?


Also, this problem happens in an old version of my program that was compiled with Delphi 4. Whoops. 此外,这个问题发生在我的程序的旧版本,使用Delphi 4编译 。哎呀。 Now I see this problem did not happen in my old version that used Delphi 4. 现在我发现在我使用Delphi 4的旧版本中没有发生这个问题。

And it was a user who reported this problem. 并且是用户报告了这个问题。 He uses Windows XP, and I'm developing on Vista, so it happens under different OS's. 他使用的是Windows XP,而我正在开发Vista,所以它发生在不同的操作系统下。


Confirmation: Yes, I create a new form and add a FindDialog on it. 确认:是的,我创建了一个新表单并在其上添加了FindDialog。 The FindDialog does NOT have the problem. FindDialog没有问题。 This indicates something in my program is causing the FindDialog to stay on top. 这表明我的程序中的某些东西导致FindDialog保持在最顶层。 Now, I've just got to find out what that is. 现在,我必须找出那是什么。 Any more ideas? 还有什么想法吗? If someone gives me an answer that even gives me a clue to help me solve this, then they'll get the accepted answer. 如果有人给我一个答案,甚至给我一个帮助我解决这个问题的线索,那么他们将得到接受的答案。


Solution: Sertac's edit to his answer gave me the workaround: 解决方案:Sertac对他的回答的编辑给了我解决方法:

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

Doing this prevents the FindDialog from being TopMost when the Application is not TopMost. 这样做可以防止FindDialog在应用程序不是TopMost时成为TopMost。

... But I still really don't understand this (the Delphi help on NormalizeTopMosts) is very confusing and doesn't indicate that it should do this. ...但我仍然真的不理解这一点(Delphi帮助NormalizeTopMosts)非常混乱,并没有表明它应该这样做。

Hopefully this "fix" won't cause other problems. 希望这个“修复”不会引起其他问题。

Looking at the VCL code, the only possible way a Find Dialog Box stays on top is, there's already a top-most window when 'Execute' is called. 查看VCL代码,查找对话框保持最佳状态的唯一可能方式是,在调用“执行”时,已经存在最顶层的窗口。 This is how it is coded, the dialog gets owned by a 'TRedirectorWindow' which gets owned by the top window in z-order in the application. 这是它的编码方式,对话框由'TRedirectorWindow'拥有,后者在应用程序中以z顺序由顶部窗口拥有。 If this 'top window' is a top-most window then the find dialog also is. 如果这个“顶部窗口”是最顶层的窗口,那么查找对话框也是。

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

or, 要么,

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


The above samples will create a top-most find dialog. 上面的示例将创建一个最顶层的查找对话框。 But a stay-on-top form possibly wouldn't go unnoticed, so I guess this wouldn't be the source of your problem. 但是一个保持顶级的形式可能不会被忽视,所以我想这不会是你的问题的根源。

In any case, it is either that or you're somehow changing the styles on the dialog by some other code piece. 在任何情况下,它或者你是以某种方式通过其他代码片段改变对话框上的样式。


BTW, do not bother testing passing various handles to FindDialog1.Execute() , it won't have an effect, see my comment to your question. 顺便说一句,不要费心测试将各种句柄传递给FindDialog1.Execute() ,它不会有效果,请看我对你的问题的评论。

edit: 编辑:

How about this one: 这个怎么样:

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

The point is, a window does not have to be visible to get enumerated by EnumThreadWindows . 关键是, EnumThreadWindows枚举的窗口不一定是可见的。 So any existing stay-on-top form could cause the find dialog to exhibit this behavior. 因此,任何现有的stay-on-top表单都可能导致查找对话框显示此行为。

Better test and see than to guess. 更好的测试和看到比猜测。 Run the below test just before you launch your Find Dialog. 在启动“查找”对话框之前运行以下测试。 This incorporates the logic 'dialogs.pas' performs to find the dialog a base, and would raise an exception if the dialog would go top-most. 这包含逻辑'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. 另一个测试可能是在启动对话框之前调用应用程序的NormalizeTopMosts ,但我知道在某些Delphi版本中,这种方法已被破坏而且无法正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM