深入了解MFC中的文挡视结构doc
- 格式:doc
- 大小:98.00 KB
- 文档页数:9
MFC文档视图结构框架分析1:程序的“导火索”---theAppCmyApp theApp;在声明对象的同时,调用其构造函数。
按C++的语法,首先要调用其基类Cwinapp的构造函数. 这个文件主要用于应用程序的一些初始化操作。
class CWinApp : public CWinThreadDECLARE_DYNAMIC(CWinApp)public:// ConstructorCWinApp(LPCTSTR lpszAppName = NULL);CWinApp::CWinApp(LPCTSTR lpszAppName)if (lpszAppName != NULL)m_pszAppName = _tcsdup(lpszAppName);elsem_pszAppName = NULL;// initialize CWinThread stateAFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;ASSERT(AfxGetThread() == NULL);pThreadState->m_pCurrentWinThread = this;ASSERT(AfxGetThread() == this);m_hThread = ::GetCurrentThread();m_nThreadID = ::GetCurrentThreadId();// initialize CWinApp stateASSERT(afxCurrentWinApp == NULL); // only one CWinApp object pleasepModuleState->m_pCurrentWinApp = this;ASSERT(AfxGetApp() == this);// in non-running state until WinMainm_hInstance = NULL;m_hLangResourceDLL = NULL;m_pszHelpFilePath = NULL;m_pszProfileName = NULL;m_pszRegistryKey = NULL;m_pszExeName = NULL;m_pRecentFileList = NULL;m_pDocManager = NULL;m_atomApp = m_atomSystemTopic = NULL;m_lpCmdLine = NULL;m_pCmdInfo = NULL;// initialize wait cursor statem_nWaitCursorCount = 0;m_hcurWaitCursorRestore = NULL;// initialize current printer statem_hDevMode = NULL;m_hDevNames = NULL;m_nNumPreviewPages = 0; // not specified (defaults to 1)// initialize DAO statem_lpfnDaoTerm = NULL; // will be set if AfxDaoInit called// other initializationm_bHelpMode = FALSE;m_eHelpType = afxWinHelp;m_nSafetyPoolSize = 512; // default size2:theApp之后的隐藏代码,由他控制整个程序的流程。
实验1 . MFC对话框应用程序练习一、上机题目:1.一个简单的单文档应用程序——记事本程序2.文档串行化编程3. 简单的班级学生查询系统(单文档多视图编程)二、上机目的:1.通过这些程序可以达到以下目的:2.文档视图框架3.文档、视图、框架之间的相互作用三、题目说明1.记事本程序利用AppWizard,自动产生一个记事本程序。
2. 文档串行化编程1)定义一个日期结构(包括年月日)置于文档对象中,在文档对象中序列化保存和读取,并在视图中显示日期信息(可以在编辑视图或普通视图中显示)。
并通过对话框修改该信息。
注:普通视图中显示文本方法:重载视图OnDraw函数,利用其中pDC->TextOut函数输出相关信息。
2)建立一个表单视图(FormView),在建立控件输入矩形的左上角和右下角,在另外一个控件中显示该视图。
注:视图会话函数:CDC* pDCTemp=m_Ctrl.GetWindowDC(); 得到视图的设备pDCTemp->Rectangle(m_x1,m_y1,m_x2,m_y2); 绘制矩形3.简单的班级学生查询系统1)建立两个视图,其中左边为一个树视图,根节点为为学院(系)(这一级至少要有两个节点如计算机学院、软件学院),二级节点为学院的系(专业)(可以只针对计算机学院输入相关二级节点,如包括网络工程、计算机科学、软件学院),右边为列表视图包含学生的姓名、学号、课程成绩等。
2)要求当选择左边的计算机学院时,右边视图显示所有计算机学院的学生信息,当选择网络工程专业,只选择网络工程专业的学生信息。
提交网站:实现步骤:例1.一个简单的单文档应用程序——记事本程序1. 只要在AppWizard的Step 6将Base Class设置为EditView,AppWizard就自动完成了一个记事本程序的设计:2. 运行程序,即可测试记事本的各种功能:3.说明:(1)打开Workshop中的Class视图,可以看到,一个简单的单文档应用程序向导自动:建立五个类(2(3)每个类的主要函数:void CAboutDlg::DoDataExchange(CDataExchange* pDX)int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)//创建窗体的工具栏,状态栏等BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)BOOL CXxxApp::InitInstance()void CXxxApp::OnAppAbout()BOOL CXxxDoc::OnNewDocument()//初始化文档字符数据、字体信息等void CXxxDoc::Serialize(CArchive& ar)BOOL CXxxView::PreCreateWindow(CREATESTRUCT& cs)void CXxxView::OnDraw(CDC* pDC)BOOL CXxxView::OnPreparePrinting(CPrintInfo* pInfo)//弹出打印对话框void CXxxView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)void CXxxView::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo)CXxxDoc* CXxxView::GetDocument() // non-debug version is inline例2.文档串行化编程将C++对象以字节流的形式保存在二进制文件中称为对象的串行化处理,经过串行化处理的称为持久对象,可以按需要在程序运行中存储和恢复。
MFC多文档和单文档视结构★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★//这一页的代码最重要了,呵呵……什么都在这里面呢;单文档新建:CWinApp_________docManager->docSingleTemplate 的OpenDocumentFile函数参数为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。
多文档新建:CWinApp_________docManager->docMultTemplate的OpenDocumentFile函数参数为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。
单文档打开:CWinApp_________docManager中经过一个打开对话框传递参数,中途还调用了APP的OpenDocumentFile,当然如果我们的APP重载了这个函数也要调用我们的但是我们的函数一定别忘记最后返回是调用父类的此函数___________docSingleTemplate的OpenDocumentFile函数参数不为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。
多文档打开:CWinApp_________docManager中经过一个打开对话框传递参数,中途还调用了APP的OpenDocumentFile,当然如果我们的APP重载了这个函数也要调用我们的但是我们的函数一定别忘记最后返回是调用父类的此函数___________docMultTemplate的OpenDocumentFile函数参数不为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。
1.1 MFC 文档视图结构程序结构总揽当我们使用MFC AppWizard 生成一个MFC 程序,选用所有默认的设置(当然也是Multiple Documents ,本文讨论主要基于Multiple Documents ,对于Single Document 情况仅以简单表述提及,皆因后者和前者很多相似相同之处,但前者更为复杂,并且更加常用。
),假设你的程序名称为A ,则你会得到CMainFrame 、CChildFrame 、CAboutDlg 、CADoc 、CAView 、CAApp 6 个类(Single Document 仅少一个CChildFrame 类,其余均同)。
这些类的具体含义将在后面给出,这里先要给出一个MFC 支持文档视图结构程序(以下简称App )的主要组成:一个App (对应类CAApp )可以包含多个文档模版(CDocTemplate ),但是MFC AppWizard (无论是SDI 还是MDI )都只是默认生成一个。
但是在实际开发中一个文档模版不够,需要自己手工添加(在后面实际项目例子提供示例)。
这个结构是通过MFC 中CWinApp 的成员变量CDocManager*m_pDocManager 实现的,我们的CAApp 正是继承自MFC 提供的CWinApp 类。
CDocManager 类则拥有一个指针链表CPtrList m_templateList 来维护这些文档模版。
这些文档模版都是在CAApp ::InitInstance ()中通过AddDocTemplate(pDocTemplate) 。
CDocTemplate 拥有3 个成员变量,分别保存着Document 、View 、Frame 的CRuntimeClass 指针,另外持有成员变量m_nIDResource ,用来指定这个Document 显示时候采用的菜单资源。
这4 份数据都在CAApp ::InitInstance ()中CDocTemplate 的构造函数中指定。
深入了解MFC中的文挡/视结构李泽宇金刚熊联欢姜军(华中理工大学图象识别与人工智能研究所)Visual C++ 5.0 以其功能强大、用户界面友好而倍受程序员们的青睐。
但是,在当前的Microsoft 基本类库4.2 版本中,大约有将近200 个类,数千个函数,加之Microsoft 公司隐藏了一些技术细节,使得人们深入学习MFC变得十分困难。
MFC的AppWizard可以生成三种类型的应用程序:基于对话框的应用、单文档应用(SDI)和多文档应用(MDI)。
前两者的结构较简单,本文不再赘叙。
笔者拟从MFC中的文档/视结构入手,分析一些函数的流程,并解决编制MDI 应用程序过程中的一些常见问题。
(一)、了解文档/视结构MFC应用程序模型历经多年以有了相当大的发展。
有一个时期,它只是个使用应用程序对象和主窗口对象的简单模型。
在这个模型中,应用程序的数据作为成员变量保持在框架窗口类中,在框架窗口的客户区中,该数据被提交显示器。
随着MFC2。
0的问世,一种应用程序结构的新方式----MFC文档/视结构出现了。
在这种结构中,CFrameWnd繁重的任务被委派给几个不同类,实现了数据存储和显示的分离。
一般情况下,采用文档/视结构的应用程序至少应由以下对象组成:。
应用程序是一个CwinApp派生对象,它充当全部应用程序的容器。
应用程序沿消息映射网络分配消息给它的所有子程序。
框架窗口是一CfrmeWnd派生对象。
文档是一个CDocument派生对象,它存储应用程序的数据,并把这些信息提供给应用程序的其余部分。
视窗是Cview派生对象,它与其父框架窗口用户区对齐。
视窗接受用户对应用程序的输入并显示相关联的文档数据。
通常,应用程序数据存在于简单模型中的框架窗口中。
在文档/视方式中,该数据移入称为document 的独立数据对象。
当然,文档不一定是文字,文档是可以表现应用程序使用的数据集的抽象术语。
而用户输入处理及图形输出功能从框架窗口转向视图。
单独的视窗完全遮蔽框架窗口的客户区,这意味着即使程序员直接绘画至框架窗口的客户区,视图仍遮蔽绘画,在屏幕上不出现任何信息。
所以输出必须通过视图。
框架窗口仅仅是个视图容器。
CDocument类对文档的建立及归档提供支持并提供应用程序用于控制其数据的接口。
MDI应用程序可以处理多个类型的文档,每个类型的文档拥有一个相关联的文档模板对象。
文档对象驻留在场景后面,提供由视图对象显示的信息。
文档至少有一个相关联的视图。
视图只能与一个文档相关联。
在文档/视方式中,对象的建立是由文档模板来管理的,它是CDocTemplate派生对象,建立并维护框架窗口,文档及视。
MFC调用命令处理程序以响应发生在应用程序中的事件。
命令发送的优先级是:活动的视图->框架窗口->文档->应用程序->默认窗口过程(DefWindowsProc) 总之,在文档/视方式中,文档和视是分离的,即:文档用于保存数据,而视是用来显示这些数据。
文档模板维护它们之间的关西。
这种文档/视结构在开发大型软件项目时特别有用。
(二)、了解与文档/视结构有关的各种类之间的关系。
在文档/视应用程序中,CWinApp 对象拥有并控制文档模板,后者产生文档、框架窗口及视窗。
这种相互关系如图(1)所示:从用户的角度来看,“视”实际上是一个普通的窗口。
象其他基于Widnows 应用的窗口一样,人们可以改变它的尺寸,对它进行移动,也可以随时关闭它。
若从程序员的角度来看,视实际上是一个从MFC 类库中的Cview 类所派生出的类的对象。
文档对象是用来保存数据的,而视对象是用来显示数据的,并且允许对数据进行编辑。
SDI 或MDI 的文档类是由Cdocument 类派生出来的,它可以有一个或多个视类,而这些视类最终都是由Cview 类派生出来的。
视对象只有一个与之相联系的文档对象,它所包含的CView::GetDocument 函数允许应用在视中得到与之相联系的文档,据此,应用程序可以对文档类成员函数及公共数据成员进行访问。
如果视对象接受到了一条消息,表示用户在编辑控制中输入了新的数据,此时,视就必须通知文档对象对其内部数据进行相应的更新。
如果文档数据发生了变化,则所有的视都必须被通知到,以便它们能够对所显示的数据进行相应的更新。
Cdocument::UpdateAllViews 函数即可完成此功能。
当该函数被调用时,派生视类的CView::OnUpdate 函数被触发。
通常OnUpdate 函数要对文档进行访问,读取文档数据,然后再对视的数据成员或控制进行更新,以便反映出文档的变化。
另外,还可以利用OnUpdate 函数使视的部分客户区无效,以便触发Cview::OnDraw 函数,利用文档数据来重新对窗口进行绘制。
在MDI 应用程序中,可以处理多个文档类型,即多个文档模板,每个模板又可以有多个文档,每个文档又可以多视显示。
为管理方便,上一级往往保留了下一级的指针列表。
如图(2)所示:解释如下:(1)、每个应用程序类(CwinApp的派生类)都保留并维护了一份所有文档模板的指针列表,这是一个链表结构。
应用程序为所要支持的每个文档类型动态分配一个CMultiDocTemplate 对象,CmultiDocTemplate(UINT nIDResource,CruntimeClass * pDocClass,CruntimeClass * pFrameClass,CruntimeClass * pViewClass );并在应用程序类的CWinApp::InitInstance成员函数中将每个CMultiDocTemplate对象传递给CWinApp::AddDocTemplate。
该函数将一个文档模板加入到应用程序可用文档模板的列表中。
函数原形为:void AddDocTemplate(CdocTemplate * pTemplate);应用程序可以用CWinApp::GetFirstDocTemplatePostion获得应用程序注册的第一个文档模板的位置,利用该值来调用CWinApp::GetNextDocTemplate函数,获得第一个CDocTemplate对象指针。
函数原形如下:POSITION GetFirstDocTemplate( ) const;CDocTemplate *GetNextDocTemplate( POSITION & pos ) const;第二个函数返回由pos 标识的文档模板。
POSITION是MFC定义的一个用于迭代或对象指针检索的值。
通过这两个函数,应用程序可以遍历整个文档模板列表。
如果被检索的文档模板是模板列表中的最后一个,则pos参数被置为NULL。
(2)、一个文档模板可以有多个文档,每个文档模板都保留并维护了一个所有对应文档的指针列表。
应用程序可以用CDocTemplate::GetFirstDocPosition函数获得与文档模板相关的文档集合中第一个文档的位置,并用POSITION值作为CDocTemplate::GetNextDoc的参数来重复遍历与模板相关的文档列表。
函数原形为:viaual POSITION GetFirstDocPosition( ) const = 0;visual Cdocument *GetNextDoc(POSITION & rPos) const = 0;如果列表为空,则rPos被置为NULL.(3)、在文档中可以调用CDocument::GetDocTemplate获得指向该文档模板的指针。
函数原形如下:CDocTemplate * GetDocTemplate ( ) const;如果该文档不属于文档模板管理,则返回值为NULL。
(4)、一个文档可以有多个视。
每一个文档都保留并维护一个所有相关视的列表。
CDocument::AddView将一个视连接到文档上,将该视加入到文档相联系的视的列表中,并将视的文档指针指向该文档。
当有File/New、File/Open、Windows/New或Window/Split的命令而将一个新创建的视的对象连接到文档上时,MFC会自动调用该函数,框架通过文档/视的结构将文档和视联系起来。
当然,程序员也可以根据自己的需要调用该函数。
Virtual POSITION GetFirstViewPosition( ) const;Virtual CViw * GetNextView( POSITION &rPosition) cosnt;应用程序可以调用CDocument::GetFirstViewPosition返回与调用文档相联系的视的列表中的第一个视的位置,并调用CDocument::GetNextView返回指定位置的视,并将rPositon的值置为列表中下一个视的POSITION值。
如果找到的视为列表中的最后一个视,则将rPosition置为NULL.当在文档上新增一个视或删除一个视时,MFC会调用OnChangeViewList函数。
如果被删除的视是该文档的最后一个视,则删除该文档。
(5)、一个视只能有一个文档。
在视中,调用CView::GetDocument可以获得一个指向视的文档的指针。
函数原形如下:CDocument *GetDocument ( ) const;如果该视不与任何文档相,则返回NULL.(6)、MDI框架窗口通过调用CFrameWnd::GetActiveDocument 可以获得与当前活动的视相连的CDocument 指针。
函数原形如下:virtual CDocument * GetActiveDocument( );(7)、通过调用CFrameWnd::GetActiveView 可以获得指向与CFrameWnd框架窗口连接的活动视的指针,如果是被CMDIFrameWnd框架窗口调用,则返回NULL。
MDI框架窗口可以首先调用MDIGetActive找到活动的MDI子窗口,然后找到该子窗口的活动视。
函数原形如下:virtual Cdocument * GetActiveDocument( );(8)、MDI框架窗口通过调用CFrameWnd::GetActiveFrame, 可以获得一个指向MDI框架窗口的活动多文档界面子窗口的指针。
(9)、CMDIChildWnd调用GetMDIFrame获得MDI框架窗口(CMDIFrameWnd)。
(10)、CWinApp 调用AfxGetMainWnd得到指向应用程序的活动主窗口的指针。
下面一段代码,就是利用CDocTemplate、CDocument和CView之间的存取关系,遍历整个文档模板、文档以及视。