Delphi,可以仅将表单模式设置为特定的父表单吗?

Posted

技术标签:

【中文标题】Delphi,可以仅将表单模式设置为特定的父表单吗?【英文标题】:Delphi, possible to make a form modal to specific parent form only? 【发布时间】:2009-01-21 01:10:29 【问题描述】:

我有一个应用程序,其中有一个主背景表单,用户只能从那里维护系统不同部分的非模态表单。非模态表单会覆盖 CreateParams 方法,因此每个表单都会在开始任务栏中显示一个按钮:

procedure TfmMaterialsPlanning.CreateParams(var Params: TCreateParams);
begin
   inherited;
   //create a new window on the task bar when this form is created
   Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
end;

实际上,用户可以打开一个维护“Apples”的非模态表单,另一个维护“Oranges”的非模态表单,并使用开始菜单栏在两者之间轻松切换。

但是,如果他们从“Apples”表单打开模态表单,例如设置选项、偏好等,然后他们在关闭模态表单之前无法使用“橙色”表单。

是否可以使模态表单仅对父表单模态?那么如果他们打开苹果的选项表,他们就不能使用苹果的维护表,但仍然可以使用橙子的维护表?

【问题讨论】:

【参考方案1】:

如果您查看 TCustomForm.ShowModal() 的源代码,您会发现 VCL 不使用 Windows API 调用来显示模式对话框,而是禁用应用程序中的所有其他表单,而显示模态形式。您当然可以尝试同样的方法,只需 Show() 表单模式对话框,然后禁用父级,然后在表单模式对话框关闭后重新启用它。需要有一个中心位置来跟踪表单模式对话框、需要重新启用的表单等等。但是,您应该彻底测试代码是否确实按照您的意愿执行,即使在应用程序之间来回切换、最小化应用程序等时也是如此。

话虽如此 - 我认为这根本不是一个好主意。它打破了 Windows 用户对应用程序行为所做的所有假设。与 Mac OS X 不同,Windows 中应用程序模式对话框和表单模式对话框之间没有区别,您应该坚持与您正在编程的平台一致的行为。

很可能有更好的方式来构建您的 UI。查看“Windows 用户体验交互指南”中dialog boxes 的相关页面。最好尽可能避免模态对话框,链接的指南显示了许多用例的更好选择。如果你限制了模态对话框的使用,也许你不再需要表单模态对话框了。

【讨论】:

如果用户有两个任务栏按钮,那么这两个窗口之一显示的模式对话框不会阻塞另一个窗口是完全符合 UI 准则的。两个任务栏按钮由同一进程托管这一事实与用户无关。我实际上会争辩说,一个模式对话框阻止两个窗口是不合适的。无论如何,丹尼尔链接到一个有效的解决方案。【参考方案2】:

这篇文章有一个很好的技巧来满足您的需求:http://blogs.teamb.com/deepakshenoy/2006/08/21/26864

摘要是在模态窗口禁用时重新启用您想要的非模态窗口。

【讨论】:

效果很好!添加一些额外的逻辑可能是个好主意,这样表单在显示自己的模式对话框时就不会向自己发送WM_REENABLED【参考方案3】:

您不能通过阻止“Apples”表单在其子表单打开时接受焦点来达到相同的效果吗?

【讨论】:

【参考方案4】:

顺便说一句(虽然这将是大量工作),解决此问题的另一种方法是 Google 的 chrome 采用的方式,其中每个“选项卡”都是一个单独的进程,但在用户看来是一个单独的集成应用程序.

即使这种方法可以实现您想要的,我也必须同意上面的评论,即这会打破用户对模态行为的假设和期望。

【讨论】:

【参考方案5】:

如果您在自己的线程中创建每个非模态表单,这是可能的。然后每个模态表单都会阻塞它所属的线程。

编辑:这应该是可能的,即使 vcl 不是线程安全的。请查看Alexeys explanation 了解如何做到这一点:

因此,如果您有一组应该存在于单独线程中的表单,请将它们放入一个 dll 中,在没有包的情况下对其进行编译并使用!它会工作并且是线程安全的。

【讨论】:

使用VCL时不可能,做GUI的东西只能从一个线程使用。 是的,但是每个 DLL 都有自己的整个 VCL 副本和自己的 Application 对象。 IMO 这并不比首先使用不同的可执行文件更好。 我现在不明白为什么 Robo 想要他所描述的那样。他问有没有可能,我说有。你说不是,我说你错了……

以上是关于Delphi,可以仅将表单模式设置为特定的父表单吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何/如果仅使用表单和数据模块重构 Delphi 程序

使用 *ngFor 时如何仅将类设置为特定元素?

我应该将 delphi tframes 用于多页表单吗?

将数据网格视图背景设置为透明

如何在提交表单和位置重定向后打开特定模式

Delphi如何访问父窗体