MFC的奇异non-modality模态对话框
作者:互联网
介绍 非程序员,模态对话框是那些拒绝消失 直到你认为,这通常是通过单击OK或取消 按钮。程序员(non-VB的)模态对话框 那些禁用直接父窗口创建之前,和 使他们的父窗口时关闭。因此一个模态的本质 对话框是你不能做任何事情直到你关闭父窗口 模态对话框。非模态的对话框中相对更有礼貌和不挑剔 他们不坚持认为允许您访问他们的父母 窗户我相信,现在,任何你可能有无穷小的疑虑 关于对话框的形式已经被完全根除。 MFC类称为CDialog CWnd派生类 专门用于创建和显示对话框在屏幕上——两个 支持模态和非模态的对话框。创建非模态的对话框 Create(),你必须摧毁他们自己使用隐藏,复制Code
DestroyWindow()
和他们的行为就像任何正常非模态的窗口。 模态对话框创建和显示使用强大的DoModal () CDialog类的方法。你关闭一个模态对话框 函数调用EndDialog()或者通过调用位置() 或虚()这两个内部调用EndDialog()。 CDialog:: EndDialog方法将调用EndDialog 在user32.dll Win32 API函数定义。EndDialog (API函数)不会立即关闭该对话框,而是将设置一个 标记将指示消息队列退出循环,破坏对话框 并启用父窗口的窗口。到目前为止一切顺利;一切都那么 和平和宁静,树上的小鸟在院子里 推特在一个美丽的声音。 non-modality因素 Win32 API支持相关功能,包括各种对话框 函数用于创建模态和非模态的对话框。有隐藏,复制像CreateDialog Code
CreateDialogXXX
函数集,隐藏,复制Code
CreateDialogIndirect
等用于创建非模态的对话框 和DialogBoxXXX组函数对话框, DialogBoxIndirect等产生模态对话框。正如前面提到的 在前一节中也有EndDialog函数 只用于模态对话框和模态对话框。非模态的对话框必须 通过调用DestroyWindow直接终止。基本的原因 你不应该试图使用EndDialog非模态的对话框 非模态的对话框不有自己的消息循环也不模态 关闭父窗口,基本上消除了的实用价值 使用EndDialog。 好了,这就是会给你一个固体 踢——基于MFC CDialog模态对话框没有模态对话框。只是在 情况下你没有读到正确的第一次,在这里再次MFC CDialog基于模态对话框没有模态对话框。我就会说这一个 第三次,但害怕被称为一只鹦鹉阻挠我这样做。开放 dlgcore.cpp并检查源代码,您将看到这个 惊人的声明是正确的。MFC CDialog类使用的隐藏,Code
CreateDialogIndirect
API函数来创建一个副本和pseudo-modal对话框 如果你查找CreateDialogIndirect MSDN上你将会看到它 用于创建一个非模态的对话框。使用MFC命令路由机制 消息映射和虚函数来实现它, 真正的模态对话框将完全破坏这种机制,因为模态 消息循环控制的范围之外MFC命令路由 机械。因此,开发人员创造一个pseudo-modal别无选择 非模态的对话框然后文档作为一个模态对话框非常强烈。 基本上这些都是总结步骤pseudo-modal时完成 创建对话框通过CDialog: DoModal - bEnableParent是一个布尔标志设置为FALSE,如果启用父窗口,然后它被禁用和隐藏,复制CodebEnableParent 创建对话框设置为TRUE使用CreateDialogIndirect消息泵维护使用CWnd:: RunModalLoop一旦模态循环退出(当CDialog:: EndDialog) 启用了父窗口对话框窗口如果bEnableParent是真的是被调用DestroyWindow和DoModal返回参数传递给隐藏,复制CodeEndDialog 正如你所看到的开发者已经确保煞费苦心 pseudo-modal对话框应该按照模态对话框。他们有 甚至试图容纳不同寻常的场景可能会有两个模态 对话框都拥有相同的父——这就是bEnableParent 发挥作用了。因此,当第二模态对话框出现,它不会设置 bEnableParent真的因为父窗口 已禁用。因此当它认为它不会启用父窗口 这正是因为另一个对话框模态到相同的父需要什么 窗口仍然活跃在屏幕上。 EndDialog -一个微小的缺陷 在本章中已经多次提到,模态对话框是 使用EndDialog驳回。让我们看看EndDialog是什么 看起来像(如果感兴趣的话,它是在dlgcore.cpp中定义的) 隐藏,复制Code
void CDialog::EndDialog(int nResult) { ASSERT(::IsWindow(m_hWnd)); if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL)) EndModalLoop(nResult); ::EndDialog(m_hWnd, nResult); }
调用CWnd::EndModalLoop退出由 CWnd::RunModalLoop很好,然后EndDialog API函数是 调用以终止模态对话框。这也很好,嘿,嘿,嘿,就等着棉花 选择分钟! !将使用EndDialog API函数 仅关闭模态对话框,但这里我们试图使用它来关闭 伪模态对话框实际上只是一个伪装成的非模态对话框 反映一种它并不真正拥有的形态。(震惊的沉默……),后 最初的震惊,让我们放松一点。毕竟这不是结束 world和EndDialog并不是一个非常有害的函数调用;它 将只尝试结束不存在的模态消息循环,并将启用 对话框窗口的父窗口。前一种尝试显然会失败 后一种尝试只会做一些我们无论如何都会做的事情 拥有,因为伪模态泵一退出,DoModal就会退出 重新启用父窗口。那么,一切都好吗?鸟儿也一样 再一次安静地鸣叫? 这个错误 还记得我们之前讨论过的“友善的父母”吗 以及我如何提到如何使用这个标志来确保 当有相同父窗口的多个模态对话框同时存在时, 属性之一时,此标志防止过早启用父窗口 模态对话框兄妹被驳回?嗯你猜怎么着?粗心的程序员 编写这个特殊函数的微软刚刚渲染了所有这些 预防措施完全无效。因为现在任何MFC模态对话框 这是关闭使用EndDialog(这也意味着OnOK和 虚,因为这些 函数将内部调用EndDialog)将启用它的父窗口 不管bEnableParent持有什么价值。这基本上 意味着如果你有两个或更多的MFC模态对话框,它们有相同的父对话框 窗口,然后当你关闭任何一个模态对话框,所有 其他模态对话框将失去它们的模态,因为现在父窗口已经失去了模态 被重新启用。 重现这个错误的步骤 创建一个基于MFC对话框的应用程序,添加一个新的对话框,并将一个名为CChildDialog的类与它关联在主对话框的OnInitDialog方法中设置两个计时器:复制CodeSetTimer(1000、1000、空); 凝固时间(2000、2000、空); 在定时器处理程序中,每个弹出一个伪模态对话框:OnTimer(UINT nIDEvent) { 消磨时间的(nIDEvent); CChildDialog dlg(这个); dlg.DoModal (); CDialog:定时(nIDEvent); } 运行程序并等待2秒,此时您将拥有主程序 对话框和两个模态子对话框试图访问主对话框,您将无法这样做,因为 两个模态对话框的出现现在使用OK或取消按钮来关闭一个子对话框,现在尝试访问主对话框,你会惊讶地看到 您将能够这样做,尽管在屏幕上存在模态对话框 我附加的项目是使用vc++创建的。NET 2003最终Beta和I 向没有这个版本的同学道歉。但后 上面提到的步骤最多只需要几分钟。什么 是如此的神奇,这个bug已经被忽略了几个版本 MFC。我检查了早在vc++ 6和有完全相同的问题。作为 在我看来,所有人要做的就是注释掉或删除调用 EndDialog API调用。我猜事情是这样的 MFC开发人员非常习惯于从 它们的包装器函数(例如,它们会调用MessageBox) API从CWnd::Messagebox内部),某人必须有 不经思考就自动输入这一行,QA人员也必须有 忽略了这个错误。这个问题一直不为人所知,因为它是 非常罕见的情况下,一个程序有一个多模态窗口体系结构 其中几个模态对话框窗口有相同的父窗口。 变通办法 好了,在微软纠正这个错误之前,我们能做的(除了 必须纠正MFC代码和重新编译MFC)是覆盖OK和 取消按钮处理程序,并使用以下代码代替默认值:- 隐藏,复制Code
{ if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL)) EndModalLoop(IDOK); // or IDCANCEL }
注意我们是如何没有调用基类的(如果我们这样做::EndDialog(…)) 我们所有的努力都白费了)。如果您想退出模态对话框 在外面的一个地方e OK/Cancel按钮处理程序,你应该使用相同的代码 除了您可能希望返回一个不同的值之外(比如IDYES) 例如)。 结论 据我所知,我可能是镇上最大的蠢蛋,而且可能会有 这是完全正当的理由,但有些东西告诉我 是一种非常遥远的偶然性。顺便说一下,我要感谢Shog9派我来 vc++ 6版本的dlgcore.cpp在一个相当晚的时间 (对他来说,这相当于我们大多数人的中午)。我也想 这里明确地指出,本文绝不是试图模仿 开发MFC库的一组令人惊叹的微软程序员。 版本历史 2003年4月5日-文章首次发表2003年4月7日-文章更新了解决问题的方法 本文转载于:http://www.diyabc.com/frontweb/news5144.html
标签:模态,non,MFC,窗口,对话框,EndDialog,CDialog 来源: https://www.cnblogs.com/Dincat/p/13462351.html