代码改变世界

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类实现现在还没有用到,先标记下。