目录
多文档视图架构
一个多文档视图架构运行后会是下面的样子:

内部的子框架窗口就相当于一个单文档视图架构,多文档视图架构就相当于在外面套一层框架窗口。
特点:可以管理多个文档(可以有多个文档类对象,即可以有多个数据)区别于单文档视图架构
模仿多文档视图架构
参与架构的类:CMDIFrameWnd(主框架窗口)、CMDIChildWnd(子框架窗口)、CWinApp(应用程序类)、CView(视图类)、CDocument(文档类)
需要用到的类:CDocTemplate(文档模板类)、CMultiDocTemplate(多文档模板类,文档模板类的子类)、CDocManager(文档管理类)
代码如下:
cpp
#include <afxwin.h>
#include "resource.h"
class CMyDoc : public CDocument{
DECLARE_DYNCREATE( CMyDoc )
};
IMPLEMENT_DYNCREATE( CMyDoc, CDocument )
class CMyView : public CView{
DECLARE_DYNCREATE( CMyView )
public:
virtual void OnDraw( CDC* pDC );
};
IMPLEMENT_DYNCREATE( CMyView, CView )
// 视图类必须重写OnDraw虚函数
void CMyView::OnDraw( CDC* pDC ){
pDC->TextOut( 100, 100, "我是视图窗口" );
}
class CMyChild : public CMDIChildWnd{
DECLARE_DYNCREATE( CMyChild )
};
IMPLEMENT_DYNCREATE( CMyChild, CMDIChildWnd )
// 继承主框架窗口类的类不能使用动态创建机制
class CMyFrameWnd : public CMDIFrameWnd{ //自己造主框架窗口类的对象
};
class CMyWinApp : public CWinApp{//自己造应用程序类的对象
public:
virtual BOOL InitInstance( );
};
BOOL CMyWinApp::InitInstance( ){
CMyFrameWnd* pFrame = new CMyFrameWnd; // new一个主框架窗口类对象
pFrame->LoadFrame( IDR_MENU1 ); // 给主框架窗口挂上菜单
m_pMainWnd = pFrame; // theApp->m_pMainWnd = 主框架窗口类对象
pFrame->ShowWindow( SW_SHOW );
pFrame->UpdateWindow( );
// new一个多文档类对象
CMultiDocTemplate* pTemplate = new CMultiDocTemplate(
IDR_MENU2, // 给子框架窗口挂上菜单
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMyChild),
RUNTIME_CLASS(CMyView)
);
//
AddDocTemplate( pTemplate );
OnFileNew( );//创建文档类对象,创建子框架类对象,创建子框架窗口,创建视图类对象,创建视图窗口,文档类对象和视图类对象关联
OnFileNew( );//创建文档类对象,创建子框架类对象,创建子框架窗口,创建视图类对象,创建视图窗口,文档类对象和视图类对象关联
OnFileNew( );//创建文档类对象,创建子框架类对象,创建子框架窗口,创建视图类对象,创建视图窗口,文档类对象和视图类对象关联
return TRUE;
}
CMyWinApp theApp; //爆破点
运行结果:

注意:需要给一个字符串资源,用于(父、子)框架窗口的标题命名
执行流程
在这里下断点,看看主框架窗口类对象的创建,this指针是pFrame主框架窗口类对象

调用函数LoadFrame(),this指针是pFrame主框架窗口类对象

调用Create函数创建

调用CreateEx函数,接下来就是之前分析的:
- 给 CREATESTRUCT cs; 结构体成员赋值
- 调用 PreCreateWindow(cs) :(1)注册窗口类(2)cs为空的成员重新赋值
- AfxHookWindowCreate(this); (1)埋个钩子,类型是WHCBD (2)this是pFrame,保存到全局变量_AFX_THREAD_STATE中
- 调用WIN API函数CreateWindowEx 创建主框架消息,消息会被钩子处理函数勾走。(1)pFrame对象与框架句柄绑定 (2)调用AfxWndProc函数

创建一个多文档模板类对象,触发构造函数,this指针是pTemplate

进入构造函数,接下来会调用父类的构造函数

赋值给多文档模板类对象的成员变量

m_doclist是多文档模板类对象pTemplate的成员变量,保存多个文档类对象地址
断言判断要求必须是空,之后的文档类对象会保存到这里

调用函数AddDocTemplate(),this指针是theApp

theApp对象的一个成员变量是m_pDocManager

调用函数AddDocTemplate(),this指针是m_pDocManager
把多文档模板类对象保存到m_templateList中

函数执行完毕,就形成下面的关系

调用函数 OnFileNew( );this指针是theApp

调用函数 OnFileNew( );this指针是theApp的成员m_pDocManager,文档管理类对象地址

取出多文档模板类对象地址,存储在pTemplate

调用函数OpenDocumentFile,函数内部this为多文档模板类对象地址


函数内部this为多文档模板类对象地址,调用函数CreateNewDocument();this指针是多文档模板类对象地址

动态创建文档类对象,并返回对象地址;
调用函数AddDocument()函数内部this为多文档模板类对象地址

将文档类对象扔到多文档模板类的链表成员中

调用CreateNewFrame函数内部this为多文档模板类对象地址

动态创建框子架类对象,并返回对象地址

创建子框架窗口

所以OnFileNew()函数,创建文档类对象,创建子框架类对象,创建子框架窗口,创建视图类对象,创建视图窗口,文档类对象和视图类对象关联
