我的应用程序基于模态表单。主窗体用 ShowModal 打开一个窗体,这个窗体用 ShowModal 打开另一个窗体,所以我们有堆叠的模态窗体。有时会出现一个问题,当我们在新表单中调用 ShowModal 时,它会隐藏在以前的表单后面,而不是显示在顶部。按下 alt+tab 后,表单返回顶部,但这不是一个好的解决方案。您是否遇到过这个问题,您是如何处理的?
编辑:
我使用德尔福 7。
你没有提到哪个版本的Delphi ...
较新的 Delphi 版本为 TCustomForm 添加了两个新属性:PopupMode 和 PopupParent。将模态对话框的 PopupParent 设置为创建该对话框的表单可确保子表单保持在其父表单之上。它通常可以解决您描述的问题。
我认为这对属性是在 Delphi 2006 中添加的,但可能是 2005 年。它们在 Delphi 2007 及更高版本中肯定存在。
编辑:在看到您使用 Delphi 7 后,我唯一的建议是,在显示您的模态表单的代码中,您禁用创建它的表单,并在返回时重新启用。这应该会阻止创建窗口接收输入,这可能有助于保持 Z 顺序正确。
像这样的东西可能有效(未经测试,因为我不再使用 D7):
procedure TForm1.ShowForm2;
begin
Self.Enabled := False;
try
with TForm2.Create(nil) do
begin
try
if ShowModal = mrOk then
// Returned OK. Do something;
finally
Free;
end;
end;
finally
Self.Enabled := True;
end;
end;
如果 Form2 创建了一个模态窗口(如您所提到的),只需重复该过程 - 禁用 Form2,创建 Form3 并以模态方式显示它,并在它返回时重新启用 Form2。确保使用 try..finally,正如我所展示的那样,如果模态表单中出现问题,则始终会重新启用创建表单。
很抱歉添加了一个单独的答案,但我做了更多的研究,其中一些表明我之前的答案(DisableProcessWindowsGhosting)没有帮助。由于我不能总是重现这个问题,我不能肯定地说。
我找到了一个似乎合适的解决方案。我在 Delphi 2007 中为 CreateParams 方法引用了代码,它非常接近(没有处理 PopupMode 的所有其他代码)。
我创建了下面的子类单元TForm
。
unit uModalForms;
interface
uses Forms, Controls, Windows;
type
TModalForm = class(TForm)
protected
procedure CreateParams(var params: TCreateParams); override;
end;
implementation
procedure TModalForm.CreateParams(var params: TCreateParams);
begin
inherited;
params.WndParent := Screen.ActiveForm.Handle;
if (params.WndParent <> 0) and (IsIconic(params.WndParent)
or not IsWindowVisible(params.WndParent)
or not IsWindowEnabled(params.WndParent)) then
params.WndParent := 0;
if params.WndParent = 0 then
params.WndParent := Application.Handle;
end;
然后我要做的是将此单元包含在一个表单单元中,然后将表单的类(在 .pas 代码文件中)从class(TForm)
更改为class(TModalForm)
它对我有用,似乎接近 CodeGear 的解决方案。
从这个链接看来,问题出在 2000/XP 中引入的“重影窗口”。您可以通过在启动时调用以下代码来禁用重影功能。
procedure DisableProcessWindowsGhosting;
var
DisableProcessWindowsGhostingProc: procedure;
begin
DisableProcessWindowsGhostingProc := GetProcAddress(
GetModuleHandle('user32.dll'),
'DisableProcessWindowsGhosting');
if Assigned(DisableProcessWindowsGhostingProc) then
DisableProcessWindowsGhostingProc;
end;
我能看到的唯一问题是,它会导致允许用户最小化、移动或关闭没有响应的应用程序的主窗口的功能出现问题。但是通过这种方式,您不必用Self.Enabled := False
代码覆盖每个调用。
只需将Visible
要打开模式的表单属性设置为False
. 然后你可以打开它,.ShowModal();
它会工作。
我发现在多个表单上使用“Always On Top”标志会导致 Z 顺序出现问题。您可能还会发现需要该BringWindowToTop
功能。
在使用内置 WinAPI ( MessageBox
) 启动消息框时,我发现传递调用窗口的句柄是必要的,以确保提示始终出现在顶部。
试试 OnShowForm:
PostMessage(Self.Handle, WM_USER_SET_FOCUS_AT_START, 0, 0);