我有一个应用程序,其中有一个主要的后台表单,从那里用户只能维护系统的不同部分的非模态表单。非模态表单覆盖了RectorParams方法,因此每个表单在开始任务栏中显示一个按钮:
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;
字符串
实际上,用户可以打开一个维护“Apple”的非模态表单,另一个维护“Orange”的非模态表单,并使用开始菜单栏轻松地在两者之间切换。
但是,如果他们从“苹果”表单打开一个模态表单,例如设置选项,首选项等,那么他们不能使用“橘子”表单,直到他们关闭模态表单。
有没有可能让一个模态表单只对父表单进行模态化?所以如果他们打开Apple的选项表单,他们就不能使用Apple的维护表单,但仍然可以使用Oranges的维护表单?
6条答案
按热度按时间lb3vh1jj1#
如果你看一下TCustomForm.ShowModal()的源代码,你会发现VCL并没有使用Windows API调用来显示模态对话框,而是在显示模态表单时禁用了应用程序中的所有其他表单。当然,你也可以尝试同样的方法,只使用Show()显示表单模态对话框,然后禁用父表单,然后在表单模态对话框关闭后重新启用它。需要有一个中心位置来跟踪表单模态对话框,需要重新启用的表单等等。但是,您应该彻底测试代码是否确实做了您想要它做的事情,即使在应用程序之间来回切换时、最小化应用程序时等等。
话虽如此-我不认为这是一个好主意。它打破了Windows用户对应用程序行为的所有假设。与Mac OS X不同,Windows中的应用程序模式和表单模式对话框之间没有区别,并且您应该坚持与您正在编程的平台一致的行为。
很可能有一种更好的方法来构建你的UI。看看“Windows用户体验交互指南”中dialog boxes的相关页面。模态对话框最好尽可能避免,链接的指南为许多用例展示了更好的替代方案。如果你限制模态对话框的使用,也许你不再需要表单模态对话框。
xggvc2p62#
这篇文章有一个很好的技巧来满足你的需求:http://blogs.teamb.com/deepakshenoy/2006/08/21/26864
总结就是当一个模态窗口禁用了非模态窗口时,重新启用你想要的非模态窗口。
qlzsbp2j3#
TeamB网站在2006年由Deepak Shenoy发布了一个解决方案,但该网站已经关闭。因此,这里是该页面的副本:
是的。通过Forms.pas中的 Delphi 源代码,在TForm.ShowModal()中调用“DisableThreadWindows”以确保所有非模态表单都处于非活动状态,当模态表单关闭时,调用“EnableThreadWindows”。这些操作只是禁用所有其他窗口,然后重新启用它们。
你可以做的是:
1.处理发送到表单的WM_ENABLE消息以设置启用状态。
1.使用“PostMessage”将自定义消息(比如WM_REENABLE)发布回表单。
1.处理WM_REENABLE自定义消息,并在处理程序中启用窗口。
所以在你的 Delphi 表单中创建一个这样的表单:
字符串
其中,WM_REENABLE之前定义为:
型
然后添加一个WM_REENABLE处理程序,如下所示:
型
现在,即使显示了模态窗口,您的表单也将处于活动状态。
注意:我尝试了以下方法,但它们不起作用:
1.在WM_ENABLE处理程序中调用EnableWindow()。
1.在WM_ENABLE处理程序中发布WM_ENABLE消息。
1.试图改变我的窗口窗口样式留在顶部。
注意:不要调用“SendMessage”而不是PostMessage,它将不一致地工作。
但是如果你问我,我101%站在@mghie一边:不要针对操作系统/平台编程。不要做一些与用户(和操作系统)期望的完全不同的事情。也许模态窗口并不像你想象的那样“模态”。检查为什么你需要将窗口“锁定”在模态状态,也许这就是你需要在架构中改变的事情。
在最坏的情况下,也许你可以将日志重新父化到模式窗口中。
qpgpyjmq4#
通过防止“Apples”窗体在其子窗体打开时接受焦点,难道不能达到同样的效果吗?
abithluo5#
顺便说一句(尽管这将是一个可怕的大量工作),解决这个问题的另一种方法是谷歌的Chrome,其中每个“标签”是一个单独的进程,但对用户来说是一个单一的集成应用程序。
即使这种方法可以实现你想要的,我也不得不同意上面的评论,这将打破用户对模态行为的假设和期望。
oxcyiej76#
这是可能的,如果你在它自己的线程中创建每个非模态表单。然后每个模态表单将阻塞它所属的线程。
编辑:这应该是可能的,即使vcl不是线程安全的。请看看Alexeys explanation如何做到这一点:
所以如果你有一组表单,它们应该存在于一个单独的线程中,然后把它们放在一个dll中,编译它而不需要包,然后使用!它会工作,并且是线程安全的。