MFC程序设计(十一)单文档架构
在MFC中,文档一般用于存储数据,视图一般用于显示文档中存储的数据。因此我们常常需要将文档和视图相关联
单文档视图架构特点
单文档:只有一个文档类对象,只能存储一份数据
单文档视图架构使用
代码书写
接下来的代码中,我们会见到MFC使用动态创建机制调用类加工厂创建的三个类对象
单文档架构的程序和我们之前写的程序存在一些区别,集中在应用程序类的InitInstance函数中
预备工作
1.由于下文代码中创建单文档模板类对象时需要一个资源,因此我们添加一个菜单资源:
这是我们添加的菜单资源,ID为ID_NEW
2.单文档视图架构程序要求我们为程序窗口的标题栏写一个名字,因此我们也需要添加一个字符串资源
注意:ID是固定的,为程序标题栏的名字
代码实现
#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 )
void CMyView::OnDraw( CDC* pDC )
{
pDC->TextOut( 100, 100, "我是视图窗口 " );
}
class CMyFrameWnd : public CFrameWnd
{
DECLARE_DYNCREATE( CMyFrameWnd )
};
IMPLEMENT_DYNCREATE( CMyFrameWnd, CFrameWnd )
class CMyWinApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CSingleDocTemplate* pTemplate = new CSingleDocTemplate( IDR_MENU1,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMyFrameWnd),
RUNTIME_CLASS(CMyView));//创建单文档模板类对象
AddDocTemplate( pTemplate );
OnFileNew( );
m_pMainWnd->ShowWindow( SW_SHOW );
m_pMainWnd->UpdateWindow( );
return TRUE;
}
CMyWinApp theApp;
执行过程
单文档视图架构的程序执行核心在于以下变量
也就是说,核心在于涉及以上对象的代码
CSingleDocTemplate* pTemplate = new CSingleDocTemplate( IDR_MENU1,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMyFrameWnd),
RUNTIME_CLASS(CMyView));
AddDocTemplate( pTemplate );
OnFileNew( );
接下来我们来观察该代码背后的原理
//单文档架构的模板类
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMyDoc), //文档类 类信息
RUNTIME_CLASS(CMyFrameWnd), //框架类 类信息
RUNTIME_CLASS(CMyView)); //视图类类信息
{
this->m_pOnlyDoc = NULL;//唯一的文档类对象地址,此处尚未保存
this->m_pDocClass = pDocClass;
this->m_pFrameClass = pFrameClass;
this->m_pViewClass = pViewClass;
//此处的this为单文档模板类的对象
//以上代码为单文档模板类的对象的成员变量赋值
}
this->AddDocTemplate(pDocTemplate);//内部this指针应用程序类
{
this->m_pDocManager = new CDocManager;//应用程序类-->文档管理成员变量
m_pDocManager->AddDocTemplate(pTemplate);//内部this指针文档管理
{
m_templateList.AddTail(pTemplate);//将单文档模板类对象地址放入链表中
//此时该链表就只有刚才存入的单文档模板类对象一个成员
}
}
//OnFileNew内部执行过程
OnFileNew( )//函数内部this为&theApp
{
m_pDocManager->OnFileNew()//函数内部this为文档管理类对象地址
{
CDocTemplate* pTemplate = m_templateList.GetHead();//取出之前在链表中存入的单文档模板类对象地址
pTemplate->OpenDocumentFile()//函数内部this为单文档模板类对象地址
{
OpenDocumentFile(..)//函数内部this为单文档模板类对象地址
{
pDocument = CreateNewDocument()//函数内部this为单文档模板类对象地址
{
CDocument* pDocument = m_pDocClass->CreateObject(); //类对象加工厂动态创建文档类对象,并返回对象地址。
AddDocument(pDocument)//函数内部this为单文档模板类对象地址
{
m_pOnlyDoc = pDocument;//此时前文代码未赋值的文档类对象地址被赋值了
}
}
pFrame = CreateNewFrame(pDocument..)//函数内部this为单文档模板类对象地址
{
CCreateContext context;
...
context.m_pCurrentDoc = pDocument;//文档类对象地址
context.m_pNewViewClass = m_pViewClass;//RUNTIME_CLASS(CMyView)
CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject(); //动态创建框架类对象,并返回对象地址
pFrame->LoadFrame(...., &context);//创建框架窗口
//后续过程看前一天的伪代码
}
}
}
}
}