文档类对象和视图对象的绑定
对于单文档结构而言,文档负责处理数据,而视图类负责显示和交互,那么视图和文档类必须形成绑定关系才行,这种绑定关系是在创建视图类窗口的时候就会形成的,MFC内部在创建视图的时候会要求我们传入一个CCreateText结构,该结构里面包含了一个m_pNewViewClass和m_pCurrentDoc,m_pNewViewClass变量保存的是你要创建的视图类的静态变量CRuntimeClass的地址,m_pCurrentDoc保存的是文档类对象的地址(还有m_pLastView,m_pCurrentFrame两个成员,是用于共享视图或者框架使用的)。
创建视图窗口成功后,视图类对象响应ON_CREATE消息的处理函数,并且把创建视图窗口的所有参数传递给该函数,其中就包括CCreateText结构,这样在内部就可以拿到文档对象和视图静态变量的地址,然后就可以将该地址保存到文档类对象的一个链表里面,让文档对象和新创建的视图类对象建立绑定关系。
由于文档类对象保存视图类静态变量地址的是链表,而类对象内部有一个参数保存文档对象的只是一个参数,所以一个文档对象可以保存多个视图类对象,但是一个类对象只能对应一个文档对象。
以下代码只是说明创建视图时和文档类绑定的过程,不是真正的代码,省略了很多内容。
CMyFrameWnd* pFrame = new CMyFrameWnd;
CMyDoc* pDoc = new CMyDoc;
CCreateContext cct;
cct.m_pCurrentDoc = pDoc;//文档类对象地址
cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);//&CMyView::classCMyView
pFrame->LoadFrame(... &cct)//函数内部this为pFrame
{
Create(...,&cct)//函数内部this为pFrame
{
CreateEx(...&cct)//函数内部this为pFrame
{
CREATESTRUCT cs;
....
cs.lpCreateParams = &cct;
::CreateWindowEx(...,&cct);//创建主框架窗口
}
}
}
//处理框架窗口的WM_CREATE消息
CFrameWnd::OnCreate( pcs )//函数内部this为pFrame,参数可以获取::CreateWindowEx的12个参数
{
CCreateContext* pContext = (CCreateContext*)pcs->lpCreateParams;//获取&cct
OnCreateHelper(pcs, pContext)//函数内部this为pFrame,pContext===&cct
{
OnCreateClient(pcs, pContext)//函数内部this为pFrame,pContext===&cct
{
CreateView(pContext..)//函数内部this为pFrame,pContext===&cct
{
CWnd* pView = pContext->m_pNewViewClass->CreateObject();
//动态创建视图类对象,并返回对象地址
pView->Create(..,pContext)//函数内部this为pView,pContext===&cct
{
CreateEx(..,pContext)//函数内部this为pView,pContext===&cct
{
CREATESTRUCT cs;
....
cs.lpCreateParams = pContext;//pContext===&cct
::CreateWindowEx(...,pContext);//创建视图窗口
}
}
}
}
}
}
//处理视图窗口的WM_CREATE消息
CView::OnCreate( pcs )//函数内部this为pView,参数可以获取::CreateWindowEx函数的12个参数
{
CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;//获取&cct
pContext->m_pCurrentDoc->AddView(pView)//函数内部this为pDoc,参数为视图类对象地址
{
m_viewList.AddTail(pView);//文档类对象用一个链表成员变量,保存视图类对象地址
pView->m_pDocument = this;//视图类对象用一个普通成员变量,保存文档类对象地址
}
}
对象关系图:

theApp对象里面成员变量m_pMainWnd保存了框架类对象地址,框架类对象成员m_pViewActive保存的是当前活动的视图类对象,视图类对象的成员m_pDocument保存的是文档类对象的地址,文档类对象里面有一个链表包含了所有视图对象的地址。
文档和视图怎么交互
首先,在文档类里定义一个变量,存储数据
CString str;
然后根据文档类的响应消息,在其消息处理函数中修改str的值,然后向所有文档类里链表所包含的对象或者其中一部分对象发送onDraw消息,各个视图类响应对应的消息处理函数,并线显示更新好的数据,这就完成了数据的交互。反过来,视图类对象响应消息时也可以获取文档类对象,从而修改文档类对象的成员。
//以下是文档类消息处理函数的内容
str = "处理消息";
UpdateAllViews(NULL);//NULL代表向所有文档类里链表所包含的对象或者其中一部分对象发送onDraw消息
//如果向指向某些视图发送消息,需要把NULL换成那些不需要更新的视图类对象地址
//这就需要获得文档类对象里面所有视图类的那个链表并取出对应的类对象地址
//MFC链表操作大概都是以下方式
POSITION pos = GetFirstViewPosition();//获取链表头节点前一个位置的迭代器
//GetFirst***Position几乎所有MFC类获取链表迭代器都是这种函数形式
GetNextView(pos);//获取下一个节点的迭代器,GetNext***
//以下是视图类->文档类
CMyDoc* doc=classView.GetDocument();//这个函数就是获取视图类的文档类对象地址
//这是因为m_pDocument是保护成员,类外拿不到,故定义一个函数,在类外可以拿到文档对象地址
CMyDoc* doc = (CMyDoc*) this->m_pDocument;
doc->str="视图类修改了我";//文档类成员一旦修改就选择是否更新视图
MFC中,文档类负责数据处理,视图类负责显示和交互。在创建视图时,通过CCreateText结构,文档和视图形成绑定。视图的ON_CREATE消息处理函数中,保存了文档对象的地址,建立链表关系。一个文档对象可以有多个视图,但一个视图只对应一个文档。交互过程包括:文档修改数据并通知视图更新,视图响应消息显示更新数据,反之亦然。
783

被折叠的 条评论
为什么被折叠?



