




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第7章 单文档和多文档文档是一个应用程序数据基本元素的集合,它构成应用程序所使用的数据单元。另外它还提供了管理和维护数据的手段。文档/视图结构的基本概念就是把对数据的管理与数据的显示分开。学习本章,读者可以掌握文档/视图结构的基本原理,掌握基于单文档和多文档的应用程序的开发。7.1 什么是文档文档/视图是一种Windows常用的应用程序形式,它将数据管理和显示分离。Visual C+的MFC应用程序框架支持3种不同的应用程序,即单文档界面、多文档界面和对话框应用程序。本节介绍文档应用程序的基本概念。7.1.1 单文档界面VS多文档界面单文档应用程序是指应用程序只可以打开一个文档,如常见的记事本
2、就是单文档的典型应用。多文档应用程序是指可以同时打开多个文档,如Windows中的Word就是多文档的典型应用。在Visual C+中可以使用应用程序向导创建基于单文档或者多文档的应用程序。在Visual C+中开发单文档和多文档应用程序时,向导隐藏了两者之间的很多差异。因此在开发两种应用程序时有很多的理念和方法是相似的。7.1.2 文档/视图结构利用Visual C+的应用程序向导可以方便地创建文档程序。当利用向导生成一个应用程序时,它所创建的各个类紧密地联系在一起。其中,数据的管理和数据的显示分别由不同的类实现,这样整个程序就构成一个文档/视图结构。Windows应用程序是基于事件驱动,或
3、者说是消息驱动的。因此整个应用程序还有一个框架类,即负责应用程序与操作系统之间的消息传递,同时协调文档/视图之间的工作。文档负责数据的管理,数据通常被保存在文档类的数据成员中,而视图类则负责数据的显示。视图可以在文档类中读取数据,并负责将数据在屏幕中显示出来。7.2 文档/视图应用程序利用Visual C+应用程序向导可以方便地创建基于文档/视图结构的应用程序。它提供了整个应用程序的框架,程序员只需要添加实现预定功能的代码即可以完成功能强大的应用程序。由于单文档和多文档的应用开发基本相同,所以本节以单文档为例介绍文档/视图应用程序。7.2.1 构建单文档应用程序创建单文档应用程序需要使用应用程
4、序向导功能。使用该功能,可以方便的创建应用程序的框架。程序员可以在此基础上添加实现预定功能的代码,从而创建实现预定功能的应用程序。【示例7.1】 通过应用程序向导,建立单文档应用程序。操作过程如下所示。(1)启动Visual C+ 6.0,选择File|New命令,弹出New对话框,如图7.1所示。图7.1 New对话框 (2)选择Projects标签,然后在列表中选择MFC AppWizardexe选项。在“Project name:”文本框中输入工程文件名test。在“Location:”文本框中指定应用程序创建的位置。单击OK按钮,弹出MFC AppWizard Step 1对话框,如图
5、7.2所示。图7.2 MFC AppWizard Step 1对话框图(3)选择Single document单选按钮。单击What language would you like your resourses in?下拉列表框的下三角按钮,选择中文中国APPWZCHS.DLL选项。单击Next按钮,弹出MFC AppWizard Step 2 of 6对话框,如图7.3所示。图7.3 MFC AppWizard Step 2 of 6对话框(4)根据程序需要是否添加数据库文件。在此选择None单选按钮。单击Next按钮,弹出MFC AppWizard Step 3 of 6对话框,如图7.4
6、所示。图7.4 MFC AppWizard Step 3 of 6对话框(5)根据需要选择文档所支持的功能。在此选择None单选按钮,单击Next按钮,弹出MFC AppWizard Step 4 of 6对话框,如图7.5所示。图7.5 MFC AppWizard Step 4 of 6对话框(6)根据需要选择文档的样式。在此保留默认设置,单击Next按钮,弹出MFC AppWizard Step 5 of 6对话框,如图7.6所示。图7.6 MFC AppWizard Step 5 of 6对话框(7)根据需要选择工程样式。如MFC使用形式等,在此保留默认设置。单击Next按钮,弹出MFC
7、 AppWizard Step 6 of 6对话框,如图7.7所示。图7.7 MFC AppWizard Step 6 of 6对话框(8)在对话框中列出向导所生成的类,同时程序员可以改变类的基类,以实现新的功能。在此不改变基类。单击Finish按钮,弹出New Project Information对话框,如图7.8所示。图7.8 New Project Information对话框说明:改变CTestView类的基类为CEditView,就可以使应用程序变为可以进行输入的文档,形式就和记事本一样。(9)该对话框中列出了新建立的应用程序中项目的详细信息,包括项目的类型、向导创建的类、文档的样
8、式特征,以及工程的目录等。单击OK按钮,此时应用程序向导已经为用户生成了一个可执行的应用程序框架。(10)选择Build|Build test.exe命令。在信息输出窗口显示编译结果如图7.8.1所示。图7.8.1 编译结果(11)选择Build|Execute test.exe命令,弹出无标题-test文档,如图7.9所示。程序生成了一个文档,单击右上角关闭按钮退出程序。虽然没有编写一行代码,应用程序向导却创建了一个文档应用程序。在此基础上就可以通过添加代码实现特定功能。上面是创建单文档应用程序的基本步骤,如果需要创建一个基于多文档的应用程序,则只需要在利用向导创建应用程序的第一步选择Mul
9、tiple document。然后根据类向导的提示生成一个基于多文档的应用程序。图7.9 执行结果注意:一般来说不是面向数据的应用或数据量很少的应用程序,不宜采用文档/视图结构。如一些工具程序包括磁盘扫描程序、时钟程序,还有一些过程控制程序等。7.2.2 单文档程序的核心消息传递在文档、窗口被创建以后,整个应用程序就开始进入Windows的消息循环。前面已经介绍了Windows的消息传递,当由于文档/视图结构将数据管理与显示分离,其消息传递更为复杂。一般来说对于Windows标准消息,例如按下键盘或者单击鼠标,这类消息将传递给框架窗口。文档不会接收到此类消息,但是有些消息可能会被文档类接收,这
10、就是WM_COMMAND消息和用户界面更新。WM_COMMAND消息首先发送给活动的视图,然后发给视图相应的文档和文档模板对象。如果此时消息没有被处理,那么消息会被传递到框架窗口和应用程序对象进行消息处理。7.3 文档/视图结构分析文档/视图框架通过联系几个不同的类实现整个应用程序。它们分别是应用程序类CWinApp、框架窗口类CFrameWnd、视图类CView、文档类CDocument类和CDocTemplate类。下面对这几个类进行分析。7.3.1 主程序类CWinAppCWinApp类是主程序类,它负责进程的启动、终止、消息循环和资源管理。在整个应用程序中利用CWinApp的成员函数I
11、nitInstance()进入MFC程序,同时其成员函数还包括消息循环、加载图标等。由于整个应用程序框架已经建立,对于CWinApp类一般不需要进行改变。7.3.2 文档类的基类CDocumentCDocument类是所有文档类的基类,它提供了文档类所需要进行的最基本的操作,例如设置文档标题、建立新文档、打开新文档等。在CDocument类中最重要的两个函数是SetModifiedFlag()和UpdateAllViews()。SetModifiedFlag()是设置一个标志位,一般在文档修改时调用该函数来设置一个标志位,当文档关闭时提示用户保存修改的内容。UpdateAllViews()则刷
12、新所有和文档关联的视图,以保证显示的是最新内容。CDocument常用函数如表7.1所示。表7.1 CDocument函数列表上面的函数中有些以虚函数的形式提供,可以重写这些函数来提供CDocument类的派生类。函函 数数 名名说说 明明const CString& GetTitle() const获得文档标题获得文档标题virtual void SetTitle( LPCTSTR lpszTitle );设置文档标题设置文档标题const CString& GetPathName() const;获得文档数据文件的路径获得文档数据文件的路径virtual void SetP
13、athName(LPCTSTR lpszPathName,BOOL bAddToMRU = TRUE );设置文档数据文件的路径设置文档数据文件的路径virtual BOOL OnNewDocuMent()建立文档建立文档virtual BOOL OnOpenDocument()打开文档打开文档virtual void OnCloseDocument()关闭文档关闭文档virtual BOOL OnSaveDocument()保存文档保存文档virtual BOOL SaveModified()查询文档的修改状态并保存修改后文档查询文档的修改状态并保存修改后文档BOOL IsModified(
14、)确定文档从最后一次存储是否被修改过确定文档从最后一次存储是否被修改过void SetModifiedFlag( BOOL bModified = TRUE );设置文档从最后一次存储是否被修改过的布尔值设置文档从最后一次存储是否被修改过的布尔值7.3.3 文档类CViewCView类提供了文档类所需要的基本功能。此类可以获得与视图相关联的文档的指针,进而获得文档中的数据。其类的常用函数如表7.2所示。表7.2 CView函数列表函函 数数说说 明明CDocument* GetDocument() const;获得指向与视图相关联的文档的指针获得指向与视图相关联的文档的指针BOOL DoPre
15、parePrinting( CPrintInfo* pInfo );打印预览或准备打印预览或准备virtual BOOL IsSelected( const CObject* pDocItem ) const;确定文档是否被选中确定文档是否被选中virtual void OnPrepareDC( CDC* pDC, CPrintInfo* pInfo = NULL );修改设备描述表修改设备描述表OnScroll():当用户滚动时,当用户滚动时,CView的响应的响应OnInitialUpdate():在类第一次构造后由在类第一次构造后由MFC调用调用OnDraw():由由MFC调用发出文档到
16、设备描述表调用发出文档到设备描述表OnUpdate():由由MFC调用对文档的修改进行响应调用对文档的修改进行响应在CView中最常用的函数是OnDraw():函数,该函数在屏幕发生变化或因为焦点的变化需要重绘时调用。没有该函数,就不可能在程序切换后保证屏幕的正确显示。若想在数据更新时强制视图更新,可调用Invalidate()方法和UpdateWindow()方法来实现。注意:尽量不要在OnDraw之外的函数调用绘图方法,那些方法不会在视图需要重新绘制的时候被自动调用。下面介绍CView类的一些派生类。CEditView:简单的文本编辑器,类似Notepad。CListView:基于列表的视
17、图,类似文件夹浏览。CTreeView:基于树状控件的视图,类似文件浏览左侧的树状结构。CRichEditView:支持多种字体、OLE和RTF格式的高级编辑器。CScrollView:支持滚动条视图。CFormView:窗体视图,支持在上边使用对话框控件。CRecordView:连接到ODBC数据库的视图。CDaoRecordView:连接到DAO数据库的视图。可以在示例7.1中的第(8)步进行设置,当选择相应的类后,可以使得文档程序拥有相应的功能。7.3.4 文档模板类CDocTemplateCDocTemplate类是文档模板,它将独立的文档、视图和框架窗口对象联系在一起。在文档/视图结
18、构中,将文档、视图和框架联系在一起的对象是CDocTemplate。在SDI中是CSingleDocTemplate,而在MDI中是CMultiDocTemplate,这两个类都是CDocTemplate的子类。CDocTemplate类中的常用函数如表7.3所示。表7.3 CDocTemplate类函数列表函函 数数说说 明明virtual BOOL GetDocString( CString& rString, enum DocStringIndex index ) const;获得与文档相关的字符串获得与文档相关的字符串virtual void LoadTemplate();加载
19、指定模板加载指定模板virtual void AddDocument( CDocument* pDoc );给文档模板添加指定的模板给文档模板添加指定的模板virtual void RemoveDocument( CDocument* pDoc );在文档模板列表中输出文档在文档模板列表中输出文档virtual CDocument* CreateNewDocument();建立文档建立文档virtual BOOL SaveAllModified();查询文档模板的修改状态并存储与之有关查询文档模板的修改状态并存储与之有关的文档的文档virtual void CloseAllDocuments(
20、BOOL bEndSession );关闭所有文档关闭所有文档virtual void SetDefaultTitle( CDocument* pDocument ) = 0; 设置文档默认标题设置文档默认标题文档、视图和框架三者之间是互相关联的,它们之间的关联通过CDocTemplate类来实现。CDocTemplate的构造函数定义如下:CDocTemplate ( UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass );从构造函数可以看出,它将文
21、档类、框架类和视图类联系在一起,使得原本独立的类相互协调,完成整个应用程序。7.3.5 框架窗口类CFrameWndCFrameWnd类主要负责框架窗口的维护工作,例如工具栏、菜单、状态栏的显示和更新。该类的常用的成员函数如表7.4所示。表7.4 CFrameWnd类函数列表在SDI中使用的是CFrameWnd,而在MDI中使用的是CMDIFrameWnd和CMDIChildWnd。函函 数数说说 明明BOOL Create();创建窗口的方法,可以重载来改变属性创建窗口的方法,可以重载来改变属性virtual BOOL LoadFrame();从资源加载框架从资源加载框架void Initi
22、alUpdateFrame( CDocument* pDoc, BOOL bMake Visible );调用所有关联的视图的调用所有关联的视图的OnInitialUpdate()void SetActiveView( CView* pViewNew, BOOL bNotify = TRUE );激活一个视图激活一个视图CView* GetActiveView() const;获取当前激活视图获取当前激活视图CWnd* CreateView( CCreateContext* pContext, UINT nID = AFX_IDW_PANE_FIRST );创建一个视图创建一个视图virtua
23、l CDocument* GetActiveDocument();获取当前激活文档获取当前激活文档void SetMessageText( LPCTSTR lpszText );void SetMessageText( UINT nID );在状态栏显示一条消息在状态栏显示一条消息7.4 单文档程序分析前面介绍了文档/视图中常用的类,本节对利用应用程序向导生成的SDI程序进行分析。在单文档应用程序中,程序的大部分初始化工作在MFC程序的入口函数InitInstance()中实现。它负责进入MFC程序,并且进入消息循环,直到收到退出消息而退出程序。7.4.1 从基本概念开始7.3节已经介绍了单文
24、档中用到的几个类,并且介绍了这些类的主要成员。在文档/视图模型中利用类构成了整个系统框架。下面首先简单分析一下应用程序构建的基本过程。先来分析InitInstance()函数中的工作。(1)在MFC框架程序中,向导都会创建一个全局变量,即CWinApp对象theApp。例如例7.1中的全局变量的定义如下:CTestApp theApp;(2)在CTestApp类的InitInstance()函数中进行初始化工作。其中动态创建文档模板pDocTemplate,在动态创建文档、视图和框架的时候文档模板将三者绑定在一起。01CSingleDocTemplate* pDocTemplate;02pDo
25、cTemplate = new CSingleDocTemplate(03IDR_MAINFRAME,04RUNTIME_CLASS(CTestDoc),05RUNTIME_CLASS(CMainFrame), / main SDI frame window06RUNTIME_CLASS(CTestView)07);(3)利用下面语句将单文档模板添加到模板链表中。AddDocTemplate(pDocTemplate);(4)执行MFC框架的命令行参数,创建空白文档窗口。CCommandLineInfo cmdInfo;ParseCommandLine(cmdInfo);(5)将文档、视图和框
26、架进行初始化,如果失败则返回。if (!ProcessShellCommand(cmdInfo)return FALSE;(6)显示窗口,更新客户区视窗并进入消息循环。m_pMainWnd-ShowWindow(SW_SHOW);m_pMainWnd-UpdateWindow();通过分析上面的每一小段程序可以看到,整个SDI程序是利用模板将文档、视图和框架绑定在一起,然后进行必要的初始化后,程序进入消息循环。在成员程序中,文档、视图和框架利用这种绑定关系进行交互从而完成数据的处理与显示,协调整个应用程序。注意:文档/视图结构并没有完全要求所有数据都属于文档类,视图类也可以有自己的数据。如果在
27、视图类中不定义任何数据,在需要时都从文档类中获取,这样做会影响程序的效率。7.4.2 理解应用程序在使用向导创建了基于单文档的应用程序之后,向导会自动生成整个文档/视图模型所需要的类,并且将这些类紧密地联系在一起。在7.4.1节已经看到了在InitInstance()函数中所进行的初始化工作。在单文档中利用各个类对各部分进行管理和操作,下面分别介绍每一个类具体实现的过程,从而分析整个应用程序。1CAboutDlg类这是关于对话框的类,在利用Visual C+向导生成对话框、单文档和多文档应用程序时,向导会默认的生成一个“关于”对话框,并且自动建立了一个消息映射。在标题栏上右击,选择弹出的快捷菜
28、单的“关于”命令,就会弹出该对话框。该类的声明在Test.cpp中实现,代码如下: 上面的代码是CAboutDlg类的声明及成员函数的实现,并且该对话框拥有自己的消息映射。用户可以在上面添加控件,并且为控件建立消息映射等。2CMainFrame 类CMainFrame 类是从CFrameWnd派生出来的类。该类作为单文档应用程序的主框架窗口,其声明如下:上面是CMainFrame类的声明,该类拥有声明DECLARE_DYNCREATE(CMainFrame)支持动态创建。同时使用AssertValid()和Dump()函数进行调试版本的诊断和合法性验证。在该类中拥有成员变量m_wndStatu
29、sBar和m_wndToolBar,负责在对状态栏和工具栏进行管理和显示等。PreCreateWindow()函数在窗口将被创建时调用,可以对窗口的样式进行修改等。OnCreate()函数响应在窗口创建时发送的WM_CREATE消息。可以看到该函数主要实现状态栏和工具栏的显示等。关于如何实现这些函数,读者可以查看类成员函数的具体代码,在此不再介绍。注意:如果想在创建应用程序后改变相关的外观,则需要直接编辑CMain Frame:PreCreate Window()函数。直接编辑还允许为应用程序的初始外观作某些额外的变化。3CTestDoc类CTestDoc类是从CDocument派生出来的类,
30、是应用程序文档类,该类的函数声明如下:CTestDoc类大部分内容和CMainFrame类基本相同,同时提供了动态创建、调试版本的诊断和合法性验证等内容。不过该类提供了两个函数OnNewDocument()和Serialize(CArchive& ar)函数。OnNewDocument()函数负责新建一个文档,Serialize(CArchive& ar)函数支持了串行化处理。关于串行化处理将在7.5节进行介绍。说明:在向导自动生成的单文档应用程序中会自动生成一些菜单命令,在选择“文件”|“打开”和“文件”|“保存”命令时会调用Serialize()函数。但此时的Seriali
31、ze()函数并没有进行数据的保存,因此不能实现数据在磁盘的存取。4CTestView类CTestView类是从CView派生出来的类。该类负责整个窗口的显示操作。对于一个显示的窗口,要改变其显示的内容则该类是必不可少的,其提供了一系列的操作支持窗口的刷新等。该类的声明如下:CTestView类负责窗口显示,该类与上面介绍的类一样,支持动态创建、调试版本的诊断和合法性验证等。同时该类中提供了OnPreparePrinting(CPrintInfo* pInfo)函数、OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)函数和OnEndPrinting(CDC*
32、 pDC, CPrintInfo* pInfo)函数,这三个函数负责进行打印工作。该类同时提供了GetDocument()函数,用来得到指向与视图相关联的文档的指针。在文档/视图模型中这个函数是非常重要的,因为文档/视图的基本概念就是将数据的存储和显示分开。数据的存储一般在在CDocument的派生类中进行串行化存储。数据的显示在CView中实现。因此得到与视图相关联的文档的指针是数据显示的前提。5CTestApp类CTestApp类是应用程序对象类,在7.4.1节已经介绍了在该类的InitInstance()函数中将各个类进行联系,创建窗口并进入消息循环的基本过程。该类的声明非常简单,如下所
33、示。上面是CTestApp类的声明部分,可以看到该类的成员函数包括InitInstance()函数,利用该函数可实现整个应用程序的初始化工作。同时该类还拥有一个成员函数OnAppAbout()函数,该函数是单击“关于”命令的消息响应函数,实现“关于”对话框的弹出。上面介绍了整个单文档应用程序中使用的5个类。整个应用程序使用应用程序类进行整个应用程序的工作。而数据的存储使用文档类,数据的显示使用视图类。应用程序主框架类将数据的显示和数据的管理两个类联系在一起。在单文档应用程序中使用类的形式封装了整个程序的操作,充分体现了面向对象的特点。说明:应用程序对象的成员函数CWinApp:OnFileNe
34、w()在选择File菜单的New命令时被调用,默认时在InitInstance()中也会被调用。原理是在InitInstance()中有一个命令行参数的执行过程。当命令行上没有参数时,函数ParseCommandLine(cmdInfo)会调用CCommandLineInfo : 把m_nShellCommand成员设置为CCommandLineInfo: FileNew,这导致ProcessShellCommand()成员函数调用OnFileNew()。用户可在InitInstance()中显式的调用OnFileNew()。7.5 文 档 操 作在文档类应用程序中经常会对文档进行一些必要的操
35、作,例如实现数据在磁盘的保存,或者添加打开新文档的功能等,这些都是利用一些常用的文档操作实现的。本节介绍实现数据保存和消息映射的几类操作。7.5.1 串行化处理程序设计中,经常需要把用户的文档数据长期的保存在磁盘中。MFC提供了串行化的机制实现对象输入到字节流,或者从字节流中读出对象。当关闭文档后,它可以将数据存储在磁盘中,同时串行化的操作也支持网络和串口的传输。在SDI应用程序中,读者可以看到这样一段代码:01void CTestDoc:Serialize(CArchive& ar)0203if (ar.IsStoring()0405/ TODO: add storing code
36、here0607else0809/ TODO: add loading code here1011这段代码是实现串行化的部分。它利用CArchive类实现串行化处理。串行化处理中。如果需要对一个新建类实现串行化,则需要增加串行化操作机制,即需要为新建类添加串行化语句,同时在文档类中添加对象数组的序列化操作。在7.6节和7.6节的例子中可以看到串行化处理的详细步骤。7.5.2 消息映射MFC的ClassWizard可以为类添加消息映射,但是有些类并不可以利用ClassWizard来添加,需要用户手动添加消息映射。因此下面介绍消息映射的知识。消息映射就是用来确定消息到来时哪个函数去处理的一个映射集
37、合。实际中消息映射是一个数组,它记录了消息的全部信息,例如消息是谁发送的,消息的参数,消息的处理函数等。例如SDI程序中的消息映射如下:01BEGIN_MESSAGE_MAP(CTestApp, CWinApp)02/AFX_MSG_MAP(CTestApp)03ON_COMMAND(ID_APP_ABOUT, OnAppAbout)04/ NOTE - the ClassWizard will add and remove mapping macros here.05/ DO NOT EDIT what you see in these blocks of generated code!06
38、/AFX_MSG_MAP07/ Standard file based document commands08ON_COMMAND(ID_FILE_NEW, CWinApp:OnFileNew)09ON_COMMAND(ID_FILE_OPEN, CWinApp:OnFileOpen)10/ Standard print setup command11ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp:OnFilePrintSetup)12END_MESSAGE_MAP()位于AFX_MSG_MAP之间的宏是由ClassWizard生成的,用户添加时应该把消息映射添
39、加在AFX_MSG_MAP后面。添加消息映射完成后,就需要在相应的类中声明该函数,同时定义函数。7.5.3 消息传递通过前面的介绍可以发现,文档/视图结构的类之间利用模板进行绑定,消息的传递十分复杂。下面对消息传递过程进行介绍。当用户选择菜单命令时,消息首先传递给当前的视图,然后传递给当前文档,再传递给当前模板,然后传给框架窗口,最后传给应用程序。如果消息在传递过程中被处理,那么消息将不再继续传递。在文档/视图应用程序中,经常需要利用视图类显示图形数据,而在文档类中保存数据,那么两者之间如何联系,又是什么时候进行联系的呢?在文档类中,经常添加数据成员以保存数据,有时在视图类中获取到数据以后需要
40、利用传递给文档类的数据成员。这时,可以利用this-GetDocument()得到当前文档对象的指针,然后访问其数据成员,保存数据。有时需要把数据显示在用户的工作区上,例如图形的显示问题。一般来说图形的显示处理函数需要放在CTestView:OnDraw()函数里,这是为了解决图形的刷新和重绘问题。关于图形的刷新和重绘将在第10章进行介绍。在CTestView:OnDraw()函数里需要得到文档类的数据时,可仍然利用this-Get Document()得到其对象的指针,然后进行数据的访问。7.6 SDI应用程序实战前面介绍了文档/视图结构的基本原理,本节结合实例讲解SDI程序设计的一般步骤。
41、【示例7.2】 编写一个SDI应用程序,可以在视图窗口输入个人信息,并实现保存功能。操作步骤如下所述。(1)根据示例7.1创建基于单文档的应用程序,并在第(8)步改变CTestView类的基类为CFormView。(2)在资源上添加控件并设置控件的ID和标题如表7.5所示。表7.5 控件列表程序运行效果如图7.10所示。控控 件件 类类 型型控控 件件 标标 题题IDStatic Text姓名IDC_STATICEdit Box IDC_nameStatic Text性别IDC_STATICEdit Box IDC_sexStatic Text学号IDC_STATICEdit Box IDC_
42、numStatic Text年龄IDC_STATICEdit Box IDC_ageStatic Text家庭住址IDC_STATICEdit Box IDC_addStatic Text联系电话联系电话IDC_STATICEdit Box IDC_telGroup Box数据操作IDC_STATICButton保存IDC_saveButton取消IDC_undoGroup Box数据浏览IDC_STATICButton上一个IDC_lastButton下一个下一个IDC_next图7.10 运行效果图(3)利用类向导为控件添加数据成员,本例中需要为所有的编辑框控件添加数据成员,如图7.11所
43、示。图7.11 添加数据成员(4)利用类向导为按钮控件单击添加响应函数。保留默认函数名。(5)利用类向导添加类CStudent,类可以从CObject的任何派生类继承,例子中选择了CEdit派生。这样可以使类进行串行化操作。在类CStudent类中添加变量如下所示。public: /在类中添加变量,实现数据保存CStringadd;/家庭住址intage;/年龄CStringname;/姓名intnum;/学号CStringsex;/性别CStringtel;/电话号码编写函数Serialize(CArchive& ar)函数如下所示。01void CStudent:Serialize
44、(CArchive& ar) 0203/串行化操作04if (ar.IsStoring()05/ storing code06araddagenamenumsexaddagenamenumsextel;/从文件中读取1112(6)在类CTestDoc.h 中添加数据成员如下:#define N 33CStudent studentN;/对象数组即添加一个对象数组,且数组大小为33个,即最多可以添加33名学生的信息。注意:将类CStudent的头文件包含进testDoc.h中,即添加语句:#include student.h(7)利用类向导添加单击“保存”按钮的消息映射,编写代码如下:
45、(8)上面的代码是得到控件的值,然后保存在数组的相应位置。再利用类向导添加单击“取消”按钮的消息映射,编写代码如下:(9)单击“取消”按钮即把所有控件的值清空。上面利用变量和控件之间的关系,即利用了DDX数据传递机制。再利用类向导添加单击“下一个”按钮的消息映射,编写代码如下:(10)上面的代码是根据当前位置得到上一个位置,然后根据数组的内容查看上一个位置的相关变量,利用DDX机制显示在编辑框中。再利用类向导添加单击“下一个”按钮的消息映射,编写代码如下:(11)在上面的操作中都是利用数组的数据进行查看的,数据的处理在CTestDoc中,因此添加语句CTestDoc *pdoc=GetDocu
46、ment();。然后把数据保存在对象数组中,在CTestDoc中进行串行化处理,即在void CTestDoc:Serialize(CArchive& ar)添加语句实现学生对象数组的串行化处理。(12)编译、连接,运行程序,结果如图7.12所示。添加数据后,单击“保存”按钮。再次添加另一学生的信息,单击“保存”按钮。选择“文件”|“保存”命令,弹出保存为对话框,如图7.13所示。输入文件名,选择目录后,单击“保存”按钮。图7.12 添加数据图图7.13 保存为对话框(13)退出应用程序后,再次运行。选择“文件”|“打开”命令,弹出打开对话框。找到刚保存的文件后,单击“打开”按钮,此时
47、程序已经打开文件。查找到31号学生的信息,如图7.14所示,单击“上一个”按钮,查找到30号学生的信息,如图7.15所示。图7.14 学生信息1图7.15 学生信息2上面的例子完整地介绍了单文档应用程序的开发,讲解了文档中的常见操作,对串行化处理进行了重点分析。在实际的应用中,维护对象数组是比较困难的,在下面的章节中将采用MFC中的集合类再次讨论串行化的应用。7.7 MFC的集合类与字符串类在7.6节中采用了数组这一数据结构存储数据。实际上MFC中提供了一些集合类以实现数据的存储和管理,从而使得对数据的存储更加方便,同时可以提高存储效率和节省存储空间。本节对MFC的集合类进行介绍。7.7.1
48、集合类介绍MFC类库的集合类包含了3种数据结构,分别是动态链表、动态数组和字典。动态链表提供有序的、非索引的双向链表。它有头、尾指针,可以从头或者尾部增加、删除元素,也可以在中间插入元素。动态数组则提供了一个大小可变的、整数索引的对象数组。字典则是把一个关键字与对象关联起来的集合。集合类非常适用于数据结构的操作,简化了用户对数据结构的构造及组织过程。在文档/视图这一将数据的管理和显示分离开来的结构中,利用集合类可以有效地实现数据的存储和管理,简化操作。MFC的集合类分为模板和非模板类两种。模板类提供了较好的数据类型,在MFC中对3种集合类的模板类封装如下所示。数组:CtypedPtrArray
49、;链表:CtypedPtrlist;字典:CTypedPtrMap。7.7.2 CTypedPtrList模板链表类CTypedPtrList模板链表类的原型如下:templateclass CTtypedPtrList:public BASE_CLASS模板参数BASE_CLASS是指向链表类的CObList或者CPtrList类型,TYPE代表存储在基类链表中的元素类型。CTypedPtrList的成员函数如表7.6所示。表7.6 CTypedPtrList的成员函数注意:BASE_CLASS只能是CObList或者CPtrList类型,其他都不可以。函函 数数说说 明明TYPE GetH
50、ead() const;获得链表头元素获得链表头元素TYPE GetTail() const;获得链表尾元素获得链表尾元素TYPE RemoveHead();从链表的头部删除元素,返回此元素从链表的头部删除元素,返回此元素TYPE RemoveTail();从链表尾删除,返回此元素从链表尾删除,返回此元素POSITION AddHead( TYPE newElement );在头部添加新元素在头部添加新元素POSITION AddTail( TYPE newElement );从尾部添加新元素从尾部添加新元素TYPE& GetNext( POSITION& rPosition
51、);获取下一个位置获取下一个位置TYPE& GetPrev(POSITION& rPosition );获取前一个位置获取前一个位置【示例7.3】 模板链表类的基本操作。下面的代码实现了使用模板链表类进行数据的基本操作。首先定义一个类,然后利用输入数据对类的数据成员进行初始化。然后利用模板链表类实现数据的保存。在结束后输出模板链表中保存的数据。具体操作步骤如下所述。(1)创建一个基于控制台的应用程序。并且添加MFC的支持。方法是选择Project|Settings命令,弹出Project Settings对话框,在General标签下的“Microsoft Foundation
52、 Classes:”下拉列表框中选择Use MFC in Shared DLL项。此时即添加了MFC动态链接库。(2)在代码编辑区域输入代码如下:分析:上面的程序就是利用模板链表类实现数据的保存。这样大大简化了对链表的各种处理。该类提供了大量的成员函数可以方便地进行数据的存储和读取。上面的例子介绍了使用模板链表类的基本方法。使用模板链表类可以方便地进行数据的存储和读取。7.7.3 字符串类在C+语言中对字符串的处理是以字符数组的形式进行的。因此在进行字符串的操作中经常需要逐个检查各个元素等。而在MFC中对字符串的操作进行了封装,出现了一个MFC类:CString类。使得在MFC应用程序中对字符
53、串的操作变得非常方便。CString类是单独提供的类,该类没有基类,它提供了对字符串操作的封装工作。该类的常用成员函数如表7.7所示。表7.7 CString类的成员函数函函 数数说说 明明int GetLength() const;获取字符串长度获取字符串长度BOOL IsEmpty() const;判断字符串是否为空判断字符串是否为空void Empty();清空字符串清空字符串TCHAR GetAt( int nIndex ) const;得到某一位置的字符得到某一位置的字符void SetAt( int nIndex, TCHAR ch );设置某一位置的字符设置某一位置的字符CStr
54、ing Left( int nCount ) const;得到左侧的得到左侧的nCount个字符组成的字符串个字符组成的字符串CString Right( int nCount ) const;得到右侧的得到右侧的nCount个字符组成的字符串个字符组成的字符串void TrimLeft();清空左侧空格清空左侧空格void TrimRight();清空右侧空格清空右侧空格void ReleaseBuffer( int nNewLength = 1 );释放字符串释放字符串BOOL LoadString( UINT nID );加载字符串加载字符串说明:CString类的定义在afx.h中,如
55、果需要使用该类,则需要添加语句#include 。如果建立的是基于MFC的工程就不用包含此头文件,因为系统已经包含了此文件。同时如果在控制台应用程序中使用该类,必须添加MFC的支持。【示例7.4】 字符串的基本操作。下面的代码实现了字符串的基本操作。具体的操作步骤如下:(1)在C+源文件中添加代码,实现对字符串的操作,代码如下:上面的过程是利用CString类对字符串进行处理,在使用CString对字符串进行处理的过程中,只要合理利用其类的成员函数就可以方便地进行字符串的操作。上面介绍了CString类的使用,在MFC应用程序中经常需要输入输出字符串。使用CString类可以方便地进行字符串的
56、处理。7.8 MDI应用程序在Visual C+中可以利用向导创建基于单文档和多文档的应用程序。虽然基于多文档的应用程序和单文档应用程序有很多相似性,但两者之间在使用上还有很多区别。本节首先对多文档应用程序进行分析,然后给出一个应用实例。7.8.1 MDI应用程序分析利用向导创建基于多文档的应用程序,可以看到它与单文档应用程序有很多区别。例如它可以打开多个文档,甚至说可以打开不同类型的文档。在Visual C+中可以看到生成的类也有所不同。在多文档应用程序中会生成一个CMainFrame类,且其父类为CMDIFrameWnd类,还会生成CChildFrame类,其父类为CMDIChildWnd
57、类。CMDIFrameWnd类是应用程序主框架窗口类,而CMDIChildWnd类是应用程序子框架窗口类。一个应用程序的主框架窗口并不是与当前的视图和文档相关联,因此必须得到当前的活动子窗口,也就是子框架窗口,然后通过该子窗口获取相关的视图和文档。在SDI程序中,主框架窗口就是文档框窗,可以采用以下方法取得当前文档和视图。取得活动文档:CMyDocument* pDoc;pDoc=(CMyDocument*)(CFrameWnd*)AfxGetApp()-m_pMainWnd)-GetActiveDocument();或pDoc=(CMyDocument*)(CFrameWnd*)AfxGet
58、MainWnd();取得活动视图:CMyView* pView;pView=(CMyView*)(CFrameWnd*)AfxGetApp()-m_pMainWnd)-GetActiveView();对于MDI程序,由于子窗口才是文档框窗,因此首先要用GetActiveFrame()取得活动子框架窗口,然后通过该子窗口获取活动文档和视图。CMDIChildWnd* pChild=(CMDIChildWnd*)(CFrameWnd*)AfxGetApp()-m_pMainWnd)-GetActiveFrame();/取得活动文档:CMyDocument* pDoc=pChild-GetActiv
59、eDocument();CMyView* pView=(CMyView*)pChild-GetActiveView();通过上面的分析可以看到,整个多文档应用程序与单文档应用程序的区别就在于,它利用了主框架窗口和子框架窗口进行了整个应用程序和当前的文档和视图之间的联系。在下面将会看到一个多文档的应用实例。7.8.2 MDI应用实例MDI和SDI有着相同的基本框架,MDI拥有子框架窗口,可以打开多个文档。本节介绍基本的多文档程序实例。【示例7.5】 创建MDI应用程序,实现利用鼠标绘制矩形程序,并实现保存功能。操作步骤如下所述。(1)利用向导创建一个多文档的应用程序。(2)在CTestView.
60、h中添加数据成员。CPoint start;/定义对象CPoint end;这是保存鼠标按下和弹起的坐标,实现画图功能。并且在构造函数中初始化为0。(3)添加一个新类,实现矩形的保存。方法是选择Insert|New Class命令,弹出New Class对话框,如图7.16所示。图7.16 New Class对话框类的名称为CPRetangle,为了实现串行化,其基类需要是CObject的子类,在此选择CEdit类。单击OK按钮。(4)在CPRetangle添加数据成员,并修改其构造函数,具体代码如下:CPRetangle(CPoint a=0,CPoint b=0);/默认参数的构造函数CPoint x;/添加变量CPoint y;上面是修改了构造函数,并且添加了两个数据成员,保存矩形的坐标
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 焙烤食品制造市场推广策略考核试卷
- 玻璃加工过程中的精度控制考核试卷
- 煤炭行业的企业家精神与创新考核试卷
- 橡胶制品的环境可持续发展战略考核试卷
- 果蔬种植资源利用与保护考核试卷
- 期货市场交易策略回测平台服务考核试卷
- 病房护理设备的多功能一体化设计考核试卷
- 化学品在防伪印刷技术中的应用考核试卷
- 电器具材料选择与应用考核试卷
- 视网膜脱离护理查房
- (正式版)SH∕T 3548-2024 石油化工涂料防腐蚀工程施工及验收规范
- MOOC 敦煌文学艺术-浙江师范大学 中国大学慕课答案
- 贯彻落实八项规定精神情况自查表
- GA/T 1073-2013生物样品血液、尿液中乙醇、甲醇、正丙醇、乙醛、丙酮、异丙醇和正丁醇的顶空-气相色谱检验方法
- 欧标电缆外径表
- 现浇箱梁盘扣式现浇支架施工方案(通过专家论证)
- 热质交换课第05讲(习题课1)
- 《美丽的集邮册》朗诵
- 直线与圆锥曲线之角形面积问题
- 电力行业顾客满意度测评办法
- 群文阅读感受动物的形象教学设计
评论
0/150
提交评论