delphi – 如何防止表单/ MsgBoxes之前的forms下移动?

很多时候,在Windows 98时代之后,我们经历了一些对话失去了Z顺序并回到了前面的forms。

例如:

Dialog1.ShowModal; Dialog1.OnClickButton() : ShowMessage('anything'); 

当MessageBox出现时,它有时不具有焦点并在Dialog1下移动。 用户对此感到困惑,他们说:我的应用程序冻结了! 但是,如果他们使用Alt + Tab移动到另一个应用程序并返回,焦点返回到MessageBox,它将成为前景窗口。

我们已经通过ShowMessage,MessageBox,正常forms以及QuickReportforms来体验这一点。

有人知道吗? 这是一个Windows错误? 你怎么能阻止它? 如何捕捉这个?

谢谢你的帮助:dd


我真的说,在Win98之后,所有的操作系​​统(Win7也)都受到这个问题的影响。 我们使用Delphi 6 Prof,所以这些属性不能使用默认的窗体。

有人说消息对话框可以用MessageBox + MB_APPLMODAL来控制。 这是个好消息,但是我们有很多旧的forms和组件,第三方工具。

因此,用forms替代来创build一个全新的应用程序是很困难的。

但我们会尝试这样做。

我认为答案是这是一半的应用程序问题和半个Windows问题。 如果Windows有时会处理这个问题,而且有时候不这样做 – 这似乎是一个Windows错误。 但是,如果我们可以强制模式窗口,那么这是一个编程错误。

有人可以向我解释什么是WS_POPUP标志的含义? 它有没有副作用?

谢谢:日

Solutions Collecting From Web of "delphi – 如何防止表单/ MsgBoxes之前的forms下移动?"

这就是PopupModePopupParent属性的用途。

例如,你可以这样做:

 Dialog1.PopupMode := pmExplicit; Dialog1.PopupParent := self; Dialog1.ShowModal; 

这告诉Windows正确的Z顺序。

对于德尔福的旧版本(在Delphi 2007之前),在表格以外的其他表格上:

 interface TMyForm = Class(TForm) protected procedure CreateParams(var Para: TCreateParams); override; end; ... implementation ... procedure TMyForm.CreateParams(var Para: TCreateParams); begin inherited; Para.Style := Para.Style or WS_POPUP; { WinXP Window manager requires this for proper Z-Ordering } // Para.WndParent:=GetActiveWindow; Para.WndParent := Application.MainForm.Handle; end; 

对于消息框,在标志中包含MB_TOPMOST:

 Application.MessageBox(PChar(amessage), PChar(atitle), otherflags or MB_TOPMOST); 

我看了这个页面和FAQ半个小时,仍然找不到如何发表评论,所以原谅我这个违反协议。

首先,我想明确一点,海报恕我直言,没有使用Windows 98.他写道:“在Windows 98时代之后”,我知道意味着他在98之后的Windows版本中遇到了这个问题。

由于我也有这个问题(CB2009),我想强调海报的问题“是Windows缺陷?”,我还没有看到答案。 如果这是一个Delphi / Builder错误,也许有办法避免它? 我看不出如何拦截所有潜在的对话是一个可行的解决方案,也避免使用fsStayOnTop。 我有一个设置窗体,需要保持在我的主窗体上,但设置窗体可以并将弹出对话框,在一定的条件下将消失在设置窗体下。

如果我能理解z顺序支持出错的地方,这将会非常有帮助,因为它可能提供了一条关于如何避免它的线索。

我最近使用的一个技巧是在创建每个表单时应用这两行代码:

 SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_APPWINDOW or WS_EX_TOPMOST); SetWindowLong(Handle, GWL_HWNDPARENT, GetDesktopWindow); 

句柄是窗体的句柄(Form1.Handle)。 WS_EX_APPWINDOW部分使每个窗口都出现在任务栏上,如果不需要额外的效果,则将其删除。

对于我的主要形式,我使用这一行:

 SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_TOPMOST); 

我也使用这个功能来帮助建立我的自定义对话框(我创建了每个对话框样式的新功能 – 错误,确认等):

 function CustomDlg(const AMessage : string; const ADlgType: TMsgDlgType; const AButtons: TMsgDlgButtons; const ADefaultButton: TMsgDlgBtn) : TForm; begin Result := CreateMessageDialog(AMessage, ADlgType, AButtons, ADefaultButton); with Result do begin SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_APPWINDOW or WS_EX_TOPMOST); SetWindowLong(Handle, GWL_HWNDPARENT, GetDesktopwindow); FormStyle := fsStayOnTop; BringToFront; end; end; 

FormStyle := fsStayOnTop; 部分是可选的,当然,但我用它来确保我的确认和错误对话总是可见的用户。

这似乎有点工作,但最终效果是我不必担心意外隐藏在其他形式后面的形式。