文档类
1 相关类CDocument类-父类是CCmdTarget类,所以,文档类也可以处理菜单等
命令消息。作用保存和管理数据。
注意事项:如何解决断言错误
2 在视图中显示文档中的数据
2.1 CView::OnInitialUpdate
作用初始化视图,在附加文档之后,显示之前,由框架调用。
2.2 CView::GetDocument
获取与视图相关的文档
2.3 CFrameWnd::InitialUpdateFrame
作用,初始化更新框架,可以引起CView::OnInitialUpdate
函数的调用。
3 创建过程
3.1 在CFrameWnd::OnCreate()函数中,通过层层调用,调用
CreateView()函数,在函数中,动态创建视图对象,并创建
视图窗口。
3.2 在CView::OnCreate()函数中,调用AddView()函数,在函数中,
文档与视图相互保存对方地址。
3.3 注意问题:
一个文档可以对应多个视图(一个文档的数据可以被多个视图
显示),一个视图只能对应一个文档。
如果有断言错误,要看出错行号,并查看Call Stack是否有默认的字符串表数据需要编写。
示例:
#include "stdafx.h" #include "resource.h" //文档类 class CMyDoc:public CDocument { public: CMyDoc() { m_strText="Data From Doc!"; } CString m_strText; }; class CDocView:public CEditView { DECLARE_DYNCREATE(CDocView); public: virtual void OnInitialUpdate(); }; IMPLEMENT_DYNCREATE(CDocView,CEditView) void CDocView::OnInitialUpdate() { CMyDoc* doc= (CMyDoc*)this->GetDocument();//获取视图对应的文档 SetWindowText(doc->m_strText); this->UpdateData(TRUE); } //窗口框架类 class CDocFrame:public CFrameWnd { }; //应用程序类 class CDocApp:public CWinApp { public: virtual BOOL InitInstance(); }; CDocApp theApp; BOOL CDocApp::InitInstance() { CDocFrame *pFrame=new CDocFrame; //动态创建视图 CCreateContext cxt; cxt.m_pCurrentDoc=new CMyDoc; cxt.m_pNewViewClass=RUNTIME_CLASS(CDocView); pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW|FWS_ADDTOTITLE,NULL,&cxt); pFrame->InitialUpdateFrame(NULL,TRUE);//这里才会调用视图的OnInitialUpdate m_pMainWnd=pFrame; pFrame->ShowWindow(SW_SHOW); pFrame->UpdateWindow(); return TRUE; }
单文档视图应用程序
1 概念只能管理一个文档
2 相关类
CWinApp-应用程序类
CFrameWnd-框架类
CView-视图类
CDocument-文档类
CDocTemplate-文档模板类
CSingleDocTemplate-单文档模板类,父类是CDocTemplate。使用
文档模板类创建但文档应用程序时,框架、视图和文档都是采用动态
创建的方式创建对象的。
CSingleDocTemplate(
UINT nIDResource,//资源ID
CRuntimeClass* pDocClass,//文档类的运行时类信息
CRuntimeClass* pFrameClass,//框架的运行时类信息
CRuntimeClass* pViewClass //视图的运行时类信息
);
3 创建过程
3.1 AddDoctemplate()-添加文档模板
{
if (m_pDocManager == NULL)
//新建文档管理类的对象
m_pDocManager = new CDocManager;
m_pDocManager->AddDocTemplate(pTemplate);
{
//将文档模板对象地址保存到链表中
m_templateList.AddTail(pTemplate);
}
}
3.2 OnFileNew()-新建文档
{
m_pDocManager->OnFileNew();
{
pTemplate->OpenDocumentFile(NULL);
{
//动态创建文档对象
pDocument = CreateNewDocument();
//动态创建框架对象和创建窗口
pFrame = CreateNewFrame(pDocument, NULL);
{
//1 动态创建框架对象
(CFrameWnd*)m_pFrameClass->CreateObject();
//2 创建框架窗口
pFrame->LoadFrame(...);
//3 接着文档类中描述的创建过程,在框架的
WM_CREATE消息处理函数中,创建视图对象和窗口;
在视图的WM_CREATE消息处理函数中,文档与视图
相互保存对方地址。
}
}
}
}
4 各个类(或者说各个对象)之间的关系
CWinApp
|->m_pDocManager (CDocManager)
|->m_templateList (CSingleDocTemplate)
|->m_pOnlyDoc (CDocument)
|->CRuntimeClass* m_pDocClass; (CDocument)
|->CRuntimeClass* m_pFrameClass; (CFramWnd)
|->CRuntimeClass* m_pViewClass; (CView)
|->m_pMainWnd (CFrameWnd)
|->m_pActiveView(CView)
|->m_pDocument (CDocument)
|->m_viewList (CView)
各个类(各个对象)之间的关系通过保存对方地址产生的
5 处理命令消息的默认先后顺序
View->Document->Frame->App
//示例:有些东西没加,选择使用MFC动态库才能运行正常
#include "stdafx.h" #include "resource.h" //文档类 class CMyDoc:public CDocument { DECLARE_DYNCREATE(CMyDoc) }; IMPLEMENT_DYNCREATE(CMyDoc,CDocument) //视图类 class CMyView:public CEditView { DECLARE_DYNCREATE(CMyView) }; IMPLEMENT_DYNCREATE(CMyView,CEditView) //应用程序类 class CMyApp:public CWinApp { public: virtual BOOL InitInstance(); }; CMyApp theApp; //框架窗口类 class CMyFrame:public CFrameWnd { DECLARE_DYNCREATE(CMyFrame) }; IMPLEMENT_DYNCREATE(CMyFrame,CFrameWnd) BOOL CMyApp::InitInstance() { //创建单文档模版对象 CSingleDocTemplate *pTemplate=new CSingleDocTemplate(IDR_MAINFRAME, RUNTIME_CLASS(CMyDoc),RUNTIME_CLASS(CMyFrame),RUNTIME_CLASS(CMyView)); //将文档模版对象添加到应用程序 AddDocTemplate(pTemplate); //新建文档 OnFileNew(); //显示更新窗口 m_pMainWnd->ShowWindow(SW_MAXIMIZE); m_pMainWnd->UpdateWindow(); return TRUE; }
多文档视图应用程序
1 概念可以管理多个文档
2 相关类
CWinApp-应用程序类
CMDIFrameWnd-多文档主框架类
CMDIChildWnd-多文档子框架类
CView-视图类
CDocument-文档类
CMultiDocTemplate-多文档模板类
多文档菜单有两个、图标也有两个,分别是主框架的和子框架的。
主框架窗口对象只有一个,而子框架窗口可以有多个。每一次新建
会创建子框架、视图和文档对象,使用文档模板创建的。
注意:要求主框架窗口的菜单,菜单项至少是两项!
3 创建
添加新建菜单的消息处理
3.1 "新建"与"新建视图"的区别
"新建",创建子框架、视图和文档共3个对象
"新建视图",只想创建子框架和视图,文档使用原有的活动视图的
文档。最终的目的,一个文档对应多个视图。
多个视图数据同步
1 捕获视图内容发生变化的消息,在消息处理函数中,将当前视图的数据
保存到文档,通知其它视图文档数据发生改变了。
1.1 消息映射,ON_CONTROL_REFLECT
1.2 通知视图数据更新,CDocument::UpdateAllViews
2 其它视图收到通知后,在函数中,将文档的新的数据显示到本视图上
2.1 CView::OnUpdate()函数,视图更新函数,被CDocument::
UpdateAllViews()函数调用。
代码示例:
// MFCmdi.cpp : Defines the entry point for the application.
//加两个菜单资源,两个ICO资源,主窗口和子窗口的分别是IDR_MAINFRAME,IDR_CHILDFRAME
#include <afxwin.h> #include <afxext.h> #include "stdafx.h" #include "resource.h" //文档类 class CMyDoc:public CDocument { DECLARE_DYNCREATE(CMyDoc) }; IMPLEMENT_DYNCREATE(CMyDoc,CDocument) //视图类 class CMyView:public CEditView { DECLARE_DYNCREATE(CMyView) }; IMPLEMENT_DYNCREATE(CMyView,CEditView) //子框架窗口类-动态创建 class CChildFrame:public CMDIChildWnd { DECLARE_DYNCREATE(CChildFrame) }; IMPLEMENT_DYNCREATE(CChildFrame,CMDIChildWnd) //主框架窗口类 class CMainFrame:public CMDIFrameWnd { DECLARE_MESSAGE_MAP() public: protected: void OnNewView(); }; //新建视图,不新建文档,让一个活动文档对应多个视图 void CMainFrame::OnNewView() { //获取活动子窗口 CChildFrame* pFrame=(CChildFrame*)GetActiveFrame(); //获取活动视图 CMyView*pView=(CMyView*)pFrame->GetActiveView(); //获取活动文档 CMyDoc* pDoc=(CMyDoc*)pView->GetDocument(); //获取文档模版 CDocTemplate*pTemplate=pDoc->GetDocTemplate(); //由模版,基于活动文档 创建新的子窗口 CChildFrame*pNewFrame= (CChildFrame*)pTemplate->CreateNewFrame(pDoc,NULL); pTemplate->InitialUpdateFrame(pNewFrame,NULL); } BEGIN_MESSAGE_MAP(CMainFrame,CMDIFrameWnd) ON_COMMAND(ID_NEW_VIEW,OnNewView) END_MESSAGE_MAP() //应用程序类 class CMyApp:public CWinApp { DECLARE_MESSAGE_MAP() public: virtual BOOL InitInstance(); protected: void OnNew(); }; BEGIN_MESSAGE_MAP(CMyApp,CWinApp) ON_COMMAND(ID_NEW,OnNew) END_MESSAGE_MAP() //新建 void CMyApp::OnNew() { this->OnFileNew(); } BOOL CMyApp::InitInstance() { CMainFrame *pFrame=new CMainFrame; pFrame->LoadFrame(IDR_MAINFRAME); m_pMainWnd=pFrame; pFrame->ShowWindow(SW_SHOW); pFrame->UpdateWindow(); CMultiDocTemplate *pTemplate=new CMultiDocTemplate( IDR_CHILDFRAME,RUNTIME_CLASS(CMyDoc), RUNTIME_CLASS(CChildFrame),RUNTIME_CLASS(CMyView)); //将文档模版对象添加到应用程序 AddDocTemplate(pTemplate); //新建文档 OnFileNew(); return TRUE; } CMyApp theApp;