MFC对话框的一些资料整理——DoModal()返回值和隐藏对话框等
2012-01-08 21:19 上帝之骰 阅读(2356) 评论(0) 编辑 收藏 举报解决了对话框不弹出的问题,顺带整理下搜索到的一堆资源。
首先是关于对话框的中文资料http://www.vczx.com/tutorial/mfc/mfc12.php,介绍很详细,详细到不想看。。。
然后是DoModal()返回值的问题,主要参考清流弯弯的博客http://blog.csdn.net/shuilan0066/article/details/5775383
MSDN对对话框的返回值描述如下:
If successful, the value of the nRetCode parameter specified in the call to EndDialog; otherwise, -1.
如果返回值是-1,那肯定就是显示失败了
如果操作成功,其返回值为由EndDialog指定的nRetCode的值,而此参数nRetCode的含义为关闭对话框所采用的方式。
也就是说,在关闭此模态对话框时,其返回值为关闭对话框时所采用的方式,它只在对话框关闭时才返回相关参数值。
默认对话框关闭方式有2种:OnOK()和OnCancel()
当使用OnOK()函数关闭对话框时,返回值为IDOK
当使用OnCancel()函数关闭对话框时,返回值为IDCANCEL
另一种关闭对话框的方式是在对话框处理程序中调用EndDialog(int nRetCode)来关闭。
该函数返回nRetCode作为DoModal()函数的返回值。在创建了一个模态对话框后,必须使用EndDialog(int nRetCode)来完成处理过程。可以在任何时候调用EndDialog,包括OnInitDialog()中,你必须在对话框显示或者输入焦点设置前调用该函数。EndDialog并不会立即关闭对话框,而是通过设置标志位的方式在当前消息处理函数返回后j尽快关闭对话框。例如
int nRet = 5; // Just any value would do!
EndDialog(nRet); // This value is returned by DoModal!
将返回5作为模态对话框的返回值。
另外,对话框的X号默认调用OnCancel()方式关闭窗口。如果需要返回特定的返回值,可利用它产生WM_CLOSE消息的特点,在OnClose()中调用EndDialog来实现。
再然后是将对话框在创建时隐藏的方法。
通过资源中VISIBLE属性隐藏对话框时,会出现对话框一闪而逝,http://www.chinaitpower.com/A/2001-10-04/746.html 这篇文章分析了模态对话框的内部机制并且给出了解决方案。
DoModal()函数获取父窗口句柄后,调用::EnableWindow(hWndParent, FALSE);然后调用CreateDlgIndirect()创建非模态对话框,在通过RunModalLoop(dwFlags)维护消息循环,来模拟模态的效果。在消息循环RunModalLoop()中,有以下语句:
BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
条件dwFlags & MLF_SHOWONIDLE 始终为TRUE。 而!(GetStyle() & WS_VISIBLE)只有在WS_VISIBLE属性没有设置的时候才会为 TRUE。这样,当我们去掉Visible 属性后 bShowIdle 就为 TRUE 了。
while (bIdle &&!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
{
ASSERT(ContinueModal());
// show the dialog when the message queue goes idle
if (bShowIdle) // 找到了
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE; // 指示下一次Idle 时不用显示对话框了
}
也就是对话框资源中即使未选中VISIBLE,窗口也会在第一次IDLE状态下显示,并在下一次Idle中隐藏。
解决方案是重写WM_SHOWWINDOW消息的处理函数。
void CTestDlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
if( GetStyle() & WS_VISIBLE ) {
CDialog::OnShowWindow(bShow, nStatus);}
else {
long Style = ::GetWindowLong(*this, GWL_STYLE);
::SetWindowLong(*this, GWL_STYLE, Style | WS_VISIBLE);
CDialog::OnShowWindow(SW_HIDE, nStatus);
}
}
使用SetWindowLong,而不是 ModifyStyle, 其实是为了加快速度,因为 ModifyStyle 内部还要调用 GetWindowLong 和 SetWindowPos。
最后是在文档视图结构的视图中显示对话框的方法,即以对话框作为视图。据说可以使用CFormView类实现现在还没有用到,先标记下。