非模态对话框

转载 2012年03月28日 10:05:57
 1 非模态对话框的特点 

  与模态对话框不同,非模态对话框不垄断用户的输入,用户打开非模态对话框后,仍然可以与其它界面进行交互。 

  非模态对话框的设计与模态对话框基本类似,也包括设计对话框模板和设计CDialog类的派生类两部分。但是,在对话框的创建和删除过程中,非模态对话框与模态对话框相比有下列不同之处: 

  •  非模态对话框的模板必须具有Visible风格,否则对话框将不可见,而模态对话框则无需设置该项风格。更保险的办法是调用CWnd::ShowWindow(SW_SHOW)来显示对话框,而不管对话框是否具有Visible风格。 

  •  非模态对话框对象是用new操作符在堆中动态创建的,而不是以成员变量的形式嵌入到别的对象中或以局部变量的形式构建在堆栈上。通常应在对话框的拥有者窗口类内声明一个指向对话框类的指针成员变量,通过该指针可访问对话框对象。 

  •  通过调用CDialog::Create函数来启动对话框,而不是CDialog::DoModal,这是模态对话框的关键所在。由于Create函数不会启动新的消息循环,对话框与应用程序共用同一个消息循环,这样对话框就不会垄断用户的输入。Create在显示了对话框后就立即返回,而DoModal是在对话框被关闭后才返回的。众所周知,在MFC程序中,窗口对象的生存期应长于对应的窗口,也就是说,不能在未关闭屏幕上窗口的情况下先把对应的窗口对象删除掉。由于在Create返回后,不能确定对话框是否已关闭,这样也就无法确定对话框对象的生存期,因此只好在堆中构建对话框对象,而不能以局部变量的形式来构建之。 

  •  必须调用CWnd::DestroyWindow而不是CDialog::EndDialog来关闭非模态对话框。调用CWnd::DestroyWindow是直接删除窗口的一般方法。由于缺省的CDialog::OnOK和CDialog::OnCancel函数均调用EndDialog,故程序员必须编写自己的OnOK和OnCancel函数并且在函数中调用DestroyWindow来关闭对话框。 

  •  因为是用new操作符构建非模态对话框对象,因此必须在对话框关闭后,用delete操作符删除对话框对象。在屏幕上一个窗口被删除后,框架会调用CWnd::PostNcDestroy,这是一个虚拟函数,程序可以在该函数中完成删除窗口对象的工作,具体代码如下
    void CModelessDialog::PostNcDestroy
    {
    delete this; //删除对象本身
    }
    这样,在删除屏幕上的对话框后,对话框对象将被自动删除。拥有者对象就不必显式的调用delete来删除对话框对象了。 

  •  必须有一个标志表明非模态对话框是否是打开的。这样做的原因是用户有可能在打开一个模态对话框的情况下,又一次选择打开命令。程序根据标志来决定是打开一个新的对话框,还是仅仅把原来打开的对话框激活。通常可以用拥有者窗口中的指向对话框对象的指针作为这种标志,当对话框关闭时,给该指针赋NULL值,以表明对话框对象已不存在了。 

    根据上面的分析,我们很容易把Register程序中的登录数据对话框改成非模态对话框。这样做的好处在于如果用户在输入数据时发现编辑视图中有错误的数据,那么不必关闭对话框,就可以在编辑视图中进行修改。 

      请读者按下面几步操作: 

      在登录数据对话框模板的属性对话框的More Styles页中选择Visible项。 

      在RegisterView.h头文件的CRegisterView类的定义中加入
    public:
    CRegisterDialog* m_pRegisterDlg;
     

      在RegisterView.h头文件的头部加入对CRegisterDialog类的声明
    class CRegisterDialog;
    加入该行的原因是在CRegisterView类中有一个CRegisterDialog类型的指针,因此必须保证CRegisterDialog类的声明出现在CRegisterView之前,否则编译时将会出错。解决这个问题有两种办法,一种办法是保证在#include “RegisterView.h”语句之前有#include “RegisterDialog.h”语句,这种办法造成了一种依赖关系,增加了编译负担,不是很好;另一种办法是在CRegisterView类的声明之前加上一个对CRegisterDialog的声明来暂时“蒙蔽”编译器,这样在有#include “RegisterView.h”语句的模块中,除非要用到CRegisterDialog类,否则不用加入#include “RegisterDialog.h”语句。 

      在RegisterDialog.cpp文件的头部的#include语句区的末尾添加下面两行
    #include "RegisterDoc.h"
    #include "RegisterView.h"
     

      利用ClassWizard为CRegisterDialog类加入OnCancel和PostNcDestroy成员函数。加入的方法是进入ClassWizard后选择Message Maps页,并在Class name栏中选择CRegisterDialog。然后,在Object IDs栏中选择IDCANCEL后,在Messages栏中双击BN_CLICKED,这就创建了OnCancel。要创建PostNcDestroy,先在Object IDs栏中选择CRegisterDialog,再在Messages栏中双击PostNcDestroy即可。

    CRegisterView类的部分代码 

     CRegisterView::CRegisterView() 

     { 

     // TODO: add construction code here 

       

     m_pRegisterDlg=NULL; //指针初始化为NULL 

     } 

       

     void CRegisterView::OnEditRegister()  

     { 

     // TODO: Add your command handler code here 

       

       

     if(m_pRegisterDlg) 

     m_pRegisterDlg->SetActiveWindow(); //激活对话框 

     else 

     { 

     //创建非模态对话框 

     m_pRegisterDlg=new CRegisterDialog(this); 

     m_pRegisterDlg->Create(IDD_REGISTER,this); 

     } 

     }
    CRegisterDialog的部分代码 

     void CRegisterDialog::PostNcDestroy()  

     { 

     // TODO: Add your specialized code here and/or call the base class 

     delete this; //删除对话框对象 

     } 

     void CRegisterDialog::OnCancel()  

     { 

     // TODO: Add extra cleanup here 

     ((CRegisterView*)m_pParent)->m_pRegisterDlg=NULL; 

     DestroyWindow(); //删除对话框  

     } 

    CRegisterView::OnEditRegister函数判断登录数据对话框是否已打开,若是,就激活对话框,否则,就创建该对话框。该函数中主要调用了下列函数: 

      调用CWnd::SetActiveWindow激活对话框,该函数的声明为
    CWnd* SetActiveWindow( );
    该函数使本窗口成为活动窗口,并返回原来活动的窗口。 

      调用CDialog::Create来显示对话框,该函数的声明为
    BOOL Create( UINT nIDTemplate, CWnd* pParentWnd = NULL );
    参数nIDTemplate是对话框模板的ID。pParentWnd指定了对话框的父窗口或拥有者。 

      当用户在登录数据对话框中点击“取消”按钮后,CRegisterDialog::OnCancel将被调用,在该函数中调用CWnd::DestroyWindow来关闭对话框,并且将CRegisterView的成员m_pRegisterDlg置为NULL以表明对话框被关闭了。调用DestroyWindow导致了对CRegisterDialog::PostNcDestroy的调用,在该函数中用delete操作符删除了CRegisterDialog对象本身。 

      编译并运行Register,现在登录数据对话框已经变成一个非模态对话框了。

    2 窗口对象的自动清除 

      一个MFC窗口对象包括两方面的内容:一是窗口对象封装的窗口,即存放在m_hWnd成员中的HWND(窗口句柄),二是窗口对象本身是一个C++对象。要删除一个MFC窗口对象,应该先删除窗口对象封装的窗口,然后删除窗口对象本身。 

      删除窗口最直接方法是调用CWnd::DestroyWindow或::DestroyWindow,前者封装了后者的功能。前者不仅会调用后者,而且会使成员m_hWnd保存的HWND无效(NULL)。如果DestroyWindow删除的是一个父窗口或拥有者窗口,则该函数会先自动删除所有的子窗口或被拥有者,然后再删除父窗口或拥有者。在一般情况下,在程序中不必直接调用DestroyWindow来删除窗口,因为MFC会自动调用DestroyWindow来删除窗口。例如,当用户退出应用程序时,会产生WM_CLOSE消息,该消息会导致MFC自动调用CWnd::DestroyWindow来删除主框架窗口,当用户在对话框内按了OK或Cancel按钮时,MFC会自动调用CWnd::DestroyWindow来删除对话框及其控件。 

      窗口对象本身的删除则根据对象创建方式的不同,分为两种情况。在MFC编程中,会使用大量的窗口对象,有些窗口对象以变量的形式嵌入在别的对象内或以局部变量的形式创建在堆栈上,有些则用new操作符创建在堆中。对于一个以变量形式创建的窗口对象,程序员不必关心它的删除问题,因为该对象的生命期总是有限的,若该对象是某个对象的成员变量,它会随着父对象的消失而消失,若该对象是一个局部变量,那么它会在函数返回时被清除。 

      对于一个在堆中动态创建的窗口对象,其生命期却是任意长的。初学者在学习C++编程时,对new操作符的使用往往不太踏实,因为用new在堆中创建对象,就不能忘记用delete删除对象。读者在学习MFC的例程时,可能会产生这样的疑问,为什么有些程序用new创建了一个窗口对象,却未显式的用delete来删除它呢?问题的答案就是有些MFC窗口对象具有自动清除的功能。 

      如前面讲述非模态对话框时所提到的,当调用CWnd::DestroyWindow或::DestroyWindow删除一个窗口时,被删除窗口的PostNcDestroy成员函数会被调用。缺省的PostNcDestroy什么也不干,但有些MFC窗口类会覆盖该函数并在新版本的PostNcDestroy中调用delete this来删除对象,从而具有了自动清除的功能。此类窗口对象通常是用new操作符创建在堆中的,但程序员不必操心用delete操作符去删除它们,因为一旦调用DestroyWindow删除窗口,对应的窗口对象也会紧接着被删除。 

      不具有自动清除功能的窗口类如下所示。这些窗口对象通常是以变量的形式创建的,无需自动清除功能。 

      所有标准的Windows控件类。 

      从CWnd类直接派生出来的子窗口对象(如用户定制的控件)。 

      切分窗口类CSplitterWnd。 

      缺省的控制条类(包括工具条、状态条和对话条)。 

      模态对话框类。 

      具有自动清除功能的窗口类如下所示,这些窗口对象通常是在堆中创建的。 


非模态对话框DLL

最近在弄一个DLL,涉及到一个非模态对话框 对话框的建立无区模态非模态,区别在于创建的方式。模态对话框是使用DoModal的方式创建,而非模态对话框的方式是: CDialog *pDlg = new ...
  • rmaly
  • rmaly
  • 2014年03月18日 15:17
  • 1388

MFC非模态对话框的创建及显示

我们需要在原对话框CMFC_Kinect_TrackingDlg设计一个按钮,点击这个按钮后弹出一个非模态对话框Color_Based_SettingDlg, 并且同时两个对话框都是激活状态,都可以...
  • denyz
  • denyz
  • 2016年03月05日 11:05
  • 940

非模态对话框的创建和销毁过程

创建非模态对画框的过程:见http://blog.csdn.net/xiaominggunchuqu/article/details/49895325   一个非模态的MFC 窗口的销毁过程: ...
  • xiaominggunchuqu
  • xiaominggunchuqu
  • 2017年01月22日 17:09
  • 444

非模态对话框的创建和关闭

CXXDlg * dlg = new CXXDlg; dlg->Create(IDD_XXX,this);
  • bojie5744
  • bojie5744
  • 2014年05月18日 21:04
  • 2585

非模态对话框的操作

与模态对话框不同,非模态对话框不垄断用户的输入,用户打开非模态对话框后,仍然可以与其它界面进行交互。 非模态对话框的设计与模态对话框基本类似,也包括设计对话框模板和设计CDialog类的派生类两部分...
  • qq_25867649
  • qq_25867649
  • 2015年08月21日 12:35
  • 849

非模态对话框的消息处理

模态对话框的处理方法是dlg.DoModel()==IDOK ....但是模态对话框的消息处理则不然,需要另外注册消息处理事件今天看到一本书中这么处理,做个记录://向winproc中注册处理事件st...
  • pxxx123
  • pxxx123
  • 2006年10月20日 19:42
  • 2320

模态对话框和非模态对话框的在关于消息处理方面的区别

Windows是一个巨大的消息驱动结构,由用户发出消息,系统响应处理。windows的消息机制:Windows是一种面向对象的体系结构,Windows环境和应用程序都是通过消息来交互的。Windows...
  • henry_sea
  • henry_sea
  • 2011年07月21日 14:38
  • 1747

VC++ 非模态对话框

声明:本人一个菜鸟,网上搜罗了很多关于VC++编程的资料,可每本资料都是涵盖面太广,难以细致。英语又太烂,所以不得意只得摸索,恐又忘记所以记在此处,若有不对的地方,烦劳指出,不胜感激。 author...
  • fym0121
  • fym0121
  • 2012年05月04日 21:57
  • 4270

非模态对话框注意点

用MFC创建非模态的对话框,和模态对话框创建方式不同,模态对话框用 dlg.DoModel()调用,而非模态对话框要用Create函数创建调用。 /*假设IDD_TEST_DLG为已经定义的对话框资...
  • EckelWei
  • EckelWei
  • 2012年10月22日 10:00
  • 9933

MFC 创建非模态对话框和销毁过程

今天项目中遇到的问题,记录下来,做个总结。 一个简单的目的是创建一个非模态对话框并在对话框关闭后将其销毁。 这里的销毁包括:销毁对话框对象资源和对话框对象指针; 首先说创建对话框: 一、模态对话框(m...
  • xiaominggunchuqu
  • xiaominggunchuqu
  • 2015年11月17日 23:29
  • 5819
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:非模态对话框
举报原因:
原因补充:

(最多只允许输入30个字)