德尔福 - 我如何找出哪个模态对话框具有焦点并将其带到前面?

ros*_*mcm 7 delphi delphi-2006

我有一个Delphi 2006应用程序,它可以弹出一个模态对话框以响应错误情况.它似乎进入一种状态,其中一个模态对话框是打开的,位于主窗体的前面,但两种形式都没有响应消息.点击其中任何一个都会给出"bonk".应用程序运行正常,UI正在更新主窗体,但您无法执行任何操作.我想主要形式下很可能还有另一个模态对话框.无论是我的还是Windows的我都不知道.

其他要点:

  • 该应用程序响应键盘快捷键确定.其中一个短片优雅地关闭了应用程序,这很有效.从那以后我一直无法重现这种情况.
  • 该应用程序有一个托盘图标.这会响应鼠标右键单击.如果我从这里最小化应用程序,主窗体最小化并显示模式对话框,仍然没有焦点.如果我恢复主窗体,事情就像它们一样,两个窗口都没有焦点.Alt-tab也有类似的结果.
  • 平台是Windows 7
  • 我在创建任何表单之前调用DisableProcessWindowsGhosting
  • 我打开模态对话框

    ModalDialog.PopupParent := MainForm ;
    ModalDialog.ShowModal ;
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果其他模态对话框打开,我推迟这些错误对话框:

    if (Application.ModalLevel = 0) then
        {open modal dialog}
    
    Run Code Online (Sandbox Code Playgroud)

我的问题有两个部分:

有没有办法以编程方式找出哪个窗口有焦点?然后,我可以为这个场景或最后的手段采取一些操作,我可以提供一个快捷键将其置于前面或采取一些规避行动(取决于对话框),如将ModalResult设置为mrCancel.

这种情况怎么会出现?通常当我在主窗体后面得到一个模态对话框时(我可以通过打开模态对话框,从托盘图标中最小化应用程序,然后再次恢复应用程序) - 应用程序主窗体在对话框前面恢复,对话框仍然保持焦点),我可以通过单击托盘图标再次将它带到前面,或者用Esc键关闭它但在这种情况下它不起作用.

**更新**

Misha的解决方案与TSaveDialog之类的非delphi对话分开.通过Application.ModalPopupMode := pmAuto ;在调用之前添加,我能够让他们工作Execute.

通过"让它工作"我的意思是在以下序列之后保存对话框在前面:

  • 打开保存对话框
  • 从托盘图标最小化应用程序
  • 从托盘图标恢复应用程序

而它没有主要形式ModalPopupMode := pmAuto.

所以我希望这些变化能够帮助解决这个问题(尚未产生).

Mis*_*sha 5

如果具有焦点的表单花费太长时间来响应消息(Form1),那么Windows认为Form1没有响应,然后Form1显示模式表单(Form2),在显示Form2并且应用程序再次处理消息后,Form1将被带到前面,从而可能"覆盖"Form2.

将它放在Application.OnIdle事件中就可以了:

  if Assigned(Screen.ActiveForm) then
  begin
    if (fsModal in Screen.ActiveForm.FormState) and
       (Application.DialogHandle <= 0)) then 
    begin
      Screen.ActiveForm.BringToFront;
    end;
  end;
Run Code Online (Sandbox Code Playgroud)


NGL*_*GLN 4

可以使用以下命令查询最后一个活动弹出窗口(VCL 或非 VCL)GetLastActivePopup

function GetTopWindow: HWND;
begin
  Result := GetLastActivePopup(Application.Handle);
  if (Result = 0) or (Result = Application.Handle) or
      not IsWindowVisible(Result) then
    Result := Screen.ActiveCustomForm.Handle;
end;
Run Code Online (Sandbox Code Playgroud)

这有点抄袭自TApplication.BringToFront

可以通过以下方式将此窗口置于前面SetForegroundWindow

SetForegroundWindow(GetTopWindow);
Run Code Online (Sandbox Code Playgroud)

请注意,这Application.BringToFront可能完全可以解决问题,但我曾经遇到过它无法正常运行的情况,但从那以后我一直无法重现这种情况。

  • 您需要检查“已分配(Screen.ActiveCustomForm)”。我正在托盘中使用“Application.ShowMainForm := False”运行我的应用程序,如果我在没有显示任何表单时调用“GetTopWindow”,它会抛出 AV。 (2认同)