我有一个Delphi 2006应用程序,它可以弹出一个模态对话框以响应错误情况。它似乎进入一种状态,其中一个模态对话框是打开的,位于主窗体的前面,但两种形式都没有响应消息。点击其中一个可以得到一个" bonk"。应用程序运行正常,UI正在更新主表单,但您无法执行任何操作。我想主要形式下很可能还有另一个模态对话框。无论是我的还是Windows的我都不知道。
其他要点:
我用
打开模态对话框ModalDialog.PopupParent := MainForm ;
ModalDialog.ShowModal ;
如果其他模态对话框打开,我会推迟这些错误对话框:
if (Application.ModalLevel = 0) then
{open modal dialog}
我的问题分为两部分:
有没有办法以编程方式找出哪个窗口有焦点?然后,我可以为这个场景或最后的手段采取一些行动,我可以提供一个快捷键将其置于前面或采取一些规避行动(取决于对话框),例如将ModalResult设置为mrCancel。
这种情况怎么会出现?通常当我在主窗体后面得到一个模态对话框时(我可以通过打开模态对话框,从托盘图标中最小化应用程序,然后再次恢复应用程序) - 应用程序主窗体在对话框前面恢复,对话框仍保留焦点),我可以通过单击托盘图标将其再次显示在前面,或者使用Esc
键将其关闭,但在这种情况下它不起作用。
的 的 **更新* *
Misha的修复与TSaveDialog之类的非delphi对话分开了。我可以在调用Application.ModalPopupMode := pmAuto ;
之前添加Execute
来让他们工作。
通过"让它工作"我的意思是在以下序列之后保存对话框在前面:
虽然它不在ModalPopupMode := pmAuto
的主窗体后面。
因此,我希望这些变化有助于(尚未产生)问题。
答案 0 :(得分: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;
答案 1 :(得分:4)
可以使用GetLastActivePopup
查询最后一个活动弹出窗口(是否为VCL):
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;
这有点复制自TApplication.BringToFront
。
将此窗口置于前面可以通过SetForegroundWindow
:
SetForegroundWindow(GetTopWindow);
请注意,Application.BringToFront
可能会完全解决这个问题,但我曾经历过它无法正常运行,这是我无法重现的情况。
答案 2 :(得分:0)
GetForegroundWindow()是您正在寻找的功能,如果您知道标题或具有模态窗口的句柄,那么它很简单。
HWND GetForegroundWindow();
检索前景窗口的句柄(用于显示窗口的窗口) 用户目前正在工作)。系统分配稍高 创建前景窗口的线程的优先级比它的优先级 到其他线程。
http://msdn.microsoft.com/en-us/library/windows/desktop/ms633505%28v=vs.85%29.aspx
答案 3 :(得分:0)
我使用Misha的解决方案并进一步工作(使用NGLN的代码)来解决rossmcm看到的问题(处理非VCL对话框)。
以下代码正在运行我的计时器:
type
TCustomFormAccess = class(TCustomForm);
if Assigned(Screen.ActiveCustomForm) then
begin
if ((fsModal in Screen.ActiveCustomForm.FormState) and
(Application.DialogHandle <= 0)) then
begin
TopWindow := GetLastActivePopup(Application.Handle);
TopWindowForm := nil;
for i := 0 to Screen.CustomFormCount - 1 do
begin
CustomFormAccess := TCustomFormAccess(Screen.CustomForms[i]);
if CustomFormAccess.WindowHandle = TopWindow then TopWindowForm := CustomFormAccess;
end;
if Assigned(TopWindowForm) and (Screen.ActiveCustomForm.Handle <> TopWindow) then
begin
Screen.ActiveCustomForm.BringToFront;
end;
end;
end;