个人觉得说的挺有道理所以转过来。
原文网址:http://www.cnblogs.com/lin1270/archive/2013/02/19/2917440.html
废话不多说,直切主题。(以下的示例说明均以MDI作为叙述)
整个程序就相当于一个 文档模板[CSingleDocTemplate/CMultiDocTemplate]列表,单文档就是只有一个模板,多文档就是有多个模板。
一个模板就包括:菜单[Menu]、文档[Doc]、框架[Frame]、视图[View]
注意,他们是一个整体。
看一下代码:
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_MDI_TETYPE, // 菜单资源ID
RUNTIME_CLASS(CMDI_testDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMDI_testView));
AddDocTemplate(pDocTemplate); // 放到模板列表中
当使用VC自动生成的代码时,编译运行,使用菜单“开始”->“新建”,会从模板列表中选择一个模板进行创建一个“整体”,最初的话,会自动生成一个新的窗口,因为最初只有一个文档模板(“整体”),所以,它自动就生成了一个。注意菜单ID,它是子框架的菜单,它与ChildFrame绑定在一起了。我们可以通过关闭所有的View窗口,就可以观察到菜单改变了,MainFrame主框架和ChildFrame在默认的情况下,它们的菜单是不同的。
请做试验:添加一个菜单,响应该菜单函数,代码就是创建一个新的模板,并加入到列表:
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_MDI_TETYPE,
RUNTIME_CLASS(CMDI_testDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMDI_testView));
AddDocTemplate(pDocTemplate);
再通过“开始”->“新建”,这个时候,你会不会发现,这个时候,就会有两个模板供你选择了,因为你已经又创建了一个模板。如下图:
说完了他们一个整体性,接下来,我们就来说说一个整体中,各个部件的关系。
1)框架 (Frame)是视图和文档的载体,视图是一个窗口,文档则不是窗口,视图是要显示在框架中的。我们看一下窗口父子关系:
从上面这两幅图对比,可以看出,视图“sfdjk”的父窗口是“MDIClient”即是类CChildFrame[它从CMDIClientWnd派生出来]的对象。
2)视图是显示文档数据的窗口。这里可以看出,文档负责管理数据,视图负责将文档中的数据显示出来。我们可以看下视图OnDraw的代码:
void CMDI_testView::OnDraw(CDC* pDC)
{
CMDI_testDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
通过GetDocument就获取了文档的指针,然后就能去文档中取数据,并在OnDraw中显示出来。我们要知道的是,视图View是有一个文档Document的指针的,这便是对应关系了。[文档并不需要一个视图指针,因为数据便是数据,它不需要去关心谁去显示它,但是事实上,它保存有与它关联的视图指针]
很多时候,我们一个文档可以会包含有多份不同类别的数据,而又想用不同的窗口显示不同类别的数据,这个时候,可以创建多个视图,一个文档是可以包含多个视图的。然后在程序中处理好视图的切换即可。我们创建一个新的视图时,如何与文档关联起来呢?见代码[主框架中,而非子框架中]:
// 文档和视图关联
CDocument* m_pDoc = ((CFrameWnd*)m_pMainWnd)->GetActiveDocument(); // 这里为什么要获取活动的文档呢?
// 因为主框架有可能含有多个模板,就有可能有多个文档[因为一个模板有一个文档就足够了,多出的文档有可能是其它模板的]
// 所以要获取活动的文档
CCreateContext context;
context.m_pCurrentDoc = m_pDoc;
// 创建视图
UINT nIDFORANOTHERVIEW = AFX_IDW_PANE_FIRST + 1;
CRect rect;
m_pAnotherView->Create(
NULL,
NULL,
WS_CHILD,
rect,
((CFrameWnd*)m_pMainWnd)->GetActiveFrame (),
nIDFORANOTHERVIEW,
&context);
通过 CCreateCContext对象进行关联。注意:因为框架是视图和文档的载体,所以框架有必要提供接口:获取活动文档、获取活动视图 [这里要注意,文档和视图虽然是对应关系,或者说有一定的包含关系,但它们并不能互相管理对方,它们只能由框架(Frame)进行统一管理]。
视图既然是显示在框架上的,那二者又如何关联起来呢?见代码:
CChildFrame * pFrm = new CChildFrame();// 框架可以是你新建或者定制的框架类
CCreateContext context;
context.m_pNewViewClass = RUNTIME_CLASS(CDemoView);// 视图可以是你想显示的视图
// context.m_pCurrentDoc = m_pDoc;// m_pDoc 就是你要关联到的文档对象
// 也可以进行文档的关联
pFrm->LoadFrame(IDR_TEST2TYPE,WS_CHILD|WS_OVERLAPPEDWINDOW, this, &context);// 菜单资源你可以修改
pFrm->ShowWindow(SW_SHOW);// 显示窗口
pFrm->InitialUpdateFrame(NULL,true);// 调用视图的 OnInitialUpdate ()和框架的 ActiveFrame (),你可以在这里设置窗口的标题
最后来说一下他们之间的关系。
Frame框架可以:
1)获取活动的Frame框架[如果没有子框架,就返回它自己]
2)获取活动的文档
2)获取/设置活动的视图
Document文档可以:
1)获取Frame框架
2)增加/删除视图
3)更新视图
4)设备所有从该文档生成的Frame框架的标题
View视图可以:[就它最可怜]
1)获取它所关心的文档
参考资料:http://blog.163.com/hzxjtx@126/blog/static/356533742009121105752954/