文档-视图之间的相互作用函数:
CView::GetDocument() :允许应用程序由视图得到与之相联系的文档。返回指向文档的指针,利用它可以对文档成员函数及公共数据成员进行访问。
CDocument::GetNextView() :可以用文档得到视图,但因为文档可以有多个视图,因而必须对每个视图调用该成员函数,一般在一循环里调用。很少使用该函数,因为应用程序框架提供了更好的方法来循环获取文档所有视图。
当编译器在视图类代码中遇到对GetDocument() 的调用时,它调用的实际上是派生视图类中的该函数,而不是CView类的中该函数,因此没有必要将它返回的指针强制转换为指向派生文档类的指针。由于CView::GetDocument() 并不是虚函数,因此下面的语句:
pView->GetDocument(); // CView* pView
调用的是基类中的GetDocument() ,所返回的是指向CDocument对象的指针。
CDocument::UpdateAllView s() :当文档数据发生变化,所有视图都必须被通知。如果是在派生文档类的成员函数中调用该函数,那么它的第一个参数pSender应为NULL,如果是在派生视图类的成员函数中被调用,则应该以如下方式将pSender参数设置为当前视图:
GetDocument()->UpdateAllViews(this);
其中的非空参数就使得应用程序框架不再通知当前的视图,因为已经假定当前视图自己进行了更新。该函数还有一些更高级用法。该函数被调用时,具体的视图被通知参看OnUpdate()。
CView::OnUpdate() :虚函数。当CDocument::UpdateAllViews() 被调用 ,该函数会被调用。该函数要对文档进行访问,读取文档的数据,然后再对视图的数据成员或控制进行更新,以便反映出文档的变化。另外,可以用该函数使视图的某部分无效以便触发视图的OnDraw(),从而进行重绘。该函数默认整个窗口矩形无效。当CDocument::UpdateAllViews() 被调用,pSender参数指向了某个特定的视图对象,那么除了该指定视图,文档的所有其他视图的OnUpdate() 都会被调用。
CView::OnInitialUpdate() :该函数除了调用OnUpdate() ,没有做其它事情。如果要在派生视图类中重载该函数,就一定要在其中调用基类的该同名函数,或者调用派生类的OnUpdate()。也可以利用派生类的该函数对视图对象进行初始化。应用程序框架在调用了视图类的OnCreate()后会立即调用该函数。OnCreate() 只能被调用一次,而该函数可以被调用多次。
CDocument::OnNewDocument() :新建。这个函数是设置文档数据成员初始值的好地方。AppWizard为派生文档类产生了重载的该函数。注意一定要保持对基类函数的调用。
最简单文档-视图程序:
如果不需要文档有多视图,只利用应用框架对文件的支持,则可以不使用UpdateAllViews() 和 OnUpdate(),只需按以下步骤创建应用程序:
1、在派生文档的头文件(AppWizard产生)中定义文档的数据成员,主要用来存储应用程序中的数据。定义成公有类型或者将派生视图类声明成文档类的友元类。
2、在派生视图类中,对 OnInitialUpdate() 虚成员函数进行重载。该函数应该对视图进行更新,以便反映出当前的文档数据。
3、在派生视图类中,让窗口消息控制函数和命令消息控制函数直接读取和更新文档数据成员,利用 GetDocument()对文档对象进行访问。
下面是在这一简单文档-视图环境事件发生的次序:
应用程序启动 CMyDocument对象被创建
CMyView对象被创建
视图窗口被创建
CMyView::OnCreate() 被调用(如果被映射的话)
CMyDocument::OnNewDocument() 被调用
CMyView::OnInitialUpdate() 被调用
视图对象被初始化
视图窗口无效
CMyView::OnDraw() 被调用
用户编辑数据 CMyView 函数对 CMyDocument 数据成员进行更新
用户退出应用程序 CMyView 对象被删除
CMyDocument 对象被删除/
CFormView 类:
具有无模式对话框的许多特点。如果用AppWizard产生一个FormView对话框,则无需设置。如果用对话框编辑器创建对话框,必须在属性里设置:Sytle=Child , Border=None, Visible=unchecked 。
CFormView 对象可接收直接来自它的控制的通知消息,也可接收来自应用程序框架的命令消息。明显区别于CDialog,同时也使得框架的主菜单或工具栏中对视图进行控制变得较为容易。
CFormView是从CView (确切是CScrollView)派生而来,不是从CDialog派生的。因此不能假设它可支持所有的CDialog成员函数,CFormView类并不包含OnInitDialog()、OnOK()、OnCancel() 虚函数,也不调用UpdateData() 和DDX函数,必须在适当的时候,通常是对控制通知消息或命令消息进行响应时,自己调用这些函数。CFormView可以使用许多CDialog类的成员函数,只须将其强制转换为 CDialog指针即可。
高级文档-视图的相互作用:
多视图应用程序的主要问题在于:如果对视图#1进行编辑,那么视图#2也要随之更新,以便反映出文档的变化,则此时就需要用到 UpdateAllViews() 和 OnUpdate() 。多视图应用程序具体开发步骤如下:
1、在派生文档类的头文件(由AppWizard产生)中定义文档的数据成员。如果需要,还可以将这些数据成员定义成私有的,并且定义一些成员函数对它们进行访问,或者将视图类声明成文档类的友元。
2、在派生视图类中,使用ClassWizard重载OnUpdate() 虚成员函数。
3、对所有的命令消息作出判断,判断哪些是针对文档的,哪些是针对视图的。然后将命令映射到相应的类。
4、在派生视图类中,允许相应的命令消息控制函数对文档数据进行更新。在它们退出之前,一定要调用CDocument::UpdateAllViews()。可以用CView::GetDocument成员函数的类型安全版本来访问视图的文档。
5、在派生文档类中,允许相应的命令消息控制函数对文档数据进行更新。在它们退出前,一定要调用CDocument::UpdateAllViews()。
下面是复杂的文档-视图之间的相互作用过程中事件发生的次序:
应用程序启动 CMyDocument对象被创建
CMyView 对象被创建
其他视图对象被创建
视图窗口被创建
CMyView::OnCreate() 被调用(如果被映射)
CDocument::OnNewDocument() 被调用
CView::OnInitialUpdate() 被调用
调用CMyView::OnUpdate
初始化视图
用户执行视图命令 CMyView函数更新CMyDocument 的数据成员
调用 CDocument::UpdateAllViews
其他视图的OnUpdate() 被调用
用户执行文档命令 CMyDocument函数对数据成员进行更新
调用CDocument::UpdateAllViews
CMyView::OnUpdate() 被调用
其他视图的OnUpdate() 被调用
用户退出应用程序 视图对象被删除
CMyDocument对象被删除
CDocument::DeleteContents() :
删除文档内容。文档被关闭时,应用程序框架会自动调用重载的 DeleteContents(),在其它一些情况下,该函数也会被调用。
CObList 类:
能够支持指向 CObject 派生类对象的指针列表。CPtrList 则保存的是 void 指针,而不是 CObject 指针。CObList另一个很重要的特性是可以包含混合的指针。