在Delphi中异步打开模态对话框

6
通常使用 ShowModal 打开对话框时,当前线程的执行会暂停直到对话框关闭。我想展示一个模态对话框,但同时在对话框仍然打开的情况下继续当前线程的执行。
“模态”指的是用户在模态对话框未关闭之前无法与应用程序中的其他窗体进行交互。
Delphi 的 ShowModal 函数提供了一个略微不同的“模态”定义,与我所需的不同:
“模态表单是指应用程序无法继续运行直到该表单关闭。”
目前我的代码类似于这样:
dialog.Parent:=self;
dialog.Show;
// keep doing stuff...

这个方法可行,但是我仍然可以与父窗口进行交互(移动、关闭等)

如何显示一个表单,使用户无法与父窗口进行交互,而不使用ShowModal?

3个回答

7

打开Delphi\Source\VCL\Forms.pas的源代码,然后打开ShowModal的实现。学习它是如何工作的。由于这是CodeGear的IP,我无法在此处复制源代码,但您可以轻松地自己完成此操作并重用其代码的部分。


1
这似乎已经奏效了。我将ShowModal拆分为两个函数:ShowModalNonBlocking和CloseModalNonBlocking。我不得不删除一些无法编译的代码行。我希望有更好的解决方案,但这是目前我找到的最佳建议。 - awmross
我知道你不能发布代码,但你能否发布一些提示,比如“在X行处分割”? - Mawg says reinstate Monica
1
@Mawg,“ShowModalNonBlocking”函数以“Show()”的调用结束。“CloseModalNonBlocking”通过向窗口发送Windows消息来启动Deactivate对话框。希望这可以帮到你? - awmross

6
即使有模态窗体打开,主线程仍然执行(否则模态窗体无法重绘自身)。
但是,模态窗体具有自己的事件循环,防止原始应用程序事件循环执行。
它们必须这样做(就像Windows消息框一样),否则您可能会将事件偷偷地返回到主事件循环中,从而创建另一个模态窗体或消息框。
这种情况完全否定了模态的整个要点:每个UI线程只能有一个模态窗体或消息框。
因此,您需要问自己这个问题:
主事件循环中哪些操作被此模态窗体阻止?
然后将这些操作移动到单独的线程中。
--jeroen

1
我不同意。ShowModal 的工作原理是禁用其他窗体,显示新窗体,然后运行消息循环。我没有看到消息循环需要属于ShowModal的任何特定原因;它可以是TApplication.Run中的消息循环。当然可以同时有多个模态对话框;只需在模态窗体内部显示另一个窗体即可。但只能有一个活动窗体,其他窗体将被禁用。 - Rob Kennedy
@Rob:有趣的想法;当模态窗口需要用户处理后才能返回到父应用程序(http://en.wikipedia.org/wiki/Modal_window)时,父应用程序如何从第一个模态窗口以外的其他地方启动新的后续模态窗口? - Jeroen Wiert Pluimers
应用程序启动第一个模态窗口的方式相同:禁用所有活动窗口并显示另一个窗口。最好使用当前活动窗口作为新窗口的父窗口。 - Rob Kennedy
这不就相当于从当前模态窗口启动一个新的模态窗口,但没有风险是由于用户当前所处的模式之外的其他原因导致了这个新窗口吗? - Jeroen Wiert Pluimers

5
只要您的对话框可见,就禁用父表单,这将防止用户与其交互。您还可以使用DisableTaskWindows来禁用所有表单,而不仅仅是父表单。它没有文档说明,但您可以在 'forms.pas' 的TCustomForm.ShowModal中看到它的使用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接