第 3 章 文档和视图
description
Transcript of 第 3 章 文档和视图
![Page 1: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/1.jpg)
第 3 章 文档和视图
![Page 2: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/2.jpg)
引言
了解文档与视图结构程序的工作原理 掌握应用程序中的菜单界面设计方法 掌握工具栏和状态栏等程序界面的设计方法 了解文档的序列化工作原理 了解使用不同的视图类编程
![Page 3: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/3.jpg)
3.1 文档与视图结构
![Page 4: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/4.jpg)
3.1.1 文档与视图结构概述 —在文档 视图结构中,文档的任务是对数据进行管理和维护。数据通常被保存在文档类的成员变量中。在 Visual C++ 2005中,文档类通过一个称为串行化 (serialize)的过程将数据保存到磁盘文件或数据库中。
MFC类库为数据的串行化提供了默认的支持,只需要在此基础上稍加修改,就可以为自定义的文档类提供串行化支持。
在MFC中主要有两种类型的文档视图结构,即单文档界面( SDI:Single Document Interface)应用程序和多文档界面(MDI:Multiple Document Interface )应用程序。
![Page 5: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/5.jpg)
SDI应用程序的 5个基类之间的关系模型如图 3.1所示。
图 3.1 SDI的基本类结构布局
创建
文档模板
CSi ngl eTempl ate
应用对象
CWi nApp
指针
指针
应用对象
CDocument
指针
框架窗口
CFrameWnd
指针
视图对象
CVi ew
指针
创建
创建
创建
![Page 6: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/6.jpg)
图 3.2 MDI的基本类结构布局
MDI应用程序的 6个基类之间的关系模型如图 3.2所示
创建
文档模板
CMul t i DocTempl ate
应用对象
CWi nApp 指针
指针
应用对象
CDocument
指针
子框架窗口
CMDI Chi l dWnd
指针
视图对象
CVi ew 指针
创建
创建
创建
应用程序框架窗口
CMDI FrameWnd
指针
父窗口
子窗口
![Page 7: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/7.jpg)
视图在文档和用户之间起中介作用,它只负责实现和修改文档数据,但不负责存储。
一个视图是一个没有边框的窗口,它位于主框架窗口区的客户区。视图是文档对外显示的窗口,但是它不能完全独立,必须依存在一个框架窗口内。
每一个文档可以有多个视图,但每个视图只能对应于一个确定的文档。
视图是文档的不同表现形式。
![Page 8: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/8.jpg)
3.1.2 文档与视图间的相互作用 文档与视图的交互是通过类的共有成员变量和成员函数来实现的。表 3.1
—给出了文档 视图结构中各类对象相互访问所采用的成员函数。
表 3.1 对象访问所需函数
当前对象 被访对象 成员函数文档 视图 GetFirstViewPosition 和
GetNextView
文档 模板 GetDocTemplate
视图 文档 GetDocument
视图 框架 GetParentFrame
框架 视图 GetActiveView
框架 文档 GetActiveDocument
MDI 主框架
MDI子框架 MDIGetActive
MDI 子框架
MDI主框架 GetParentFrame
任何位置 应用程序 AfxGetApp
任何位置 主框架 AfxGetMainWnd
![Page 9: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/9.jpg)
3.1.3 多文档应用程序
Visual C++ 2005中的一个多文档应用程序有一个主窗口,在主窗口中可以同时打开多个子窗口,每一个子窗口对应一个不同的文档。
利用MFC 应用程序向导可以很方便地建立一个多文档应用程序。
![Page 10: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/10.jpg)
1.多文档应用程序
【例 3.1】编写一个多文档应用程序MyMdi,程序运行后“在客户区窗口显示信息 这是 hello world ”的多文档程序! 。
![Page 11: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/11.jpg)
程序的实现过程如下:
( 1)创建应用程序框架 ( 2)添加代码 在 MyMdi 应用程序的 CMyMdiView 类的 OnDraw 函数中
添加显示文本的代码 pDC->TextOut(50,50, _T("欢迎学习建立多文档程序! ")); TextOut函数用于在指定的位置输出字符串。
![Page 12: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/12.jpg)
2.文档模板
在文档 -视图结构应用程序中,数据以文档类的对象形式存在。
MFC提供了抽象基类 CDocTemplate来实现文档模板的功能,应用程序不能直接使用,但可以把文档模板定义为CDocTemplate的派生类,在应用程序中,必须为每种类
型的文档建立一个文档模板。
![Page 13: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/13.jpg)
( 1)文档模板的构成 文档模板定义了三个类之间的关系。 ① 文档类
应用程序从 CDocument类派生此类,用于完成文档的新建、打开和保存等工作。
② 视图类应用程序从 CView、 CScrollView、 CEditView类派生而来,用于显示文档数据。
③ 含有该视图文档的框架窗口类单文档应用程序从 CFrameWnd类派生此类,多文档应用程序从 CMDIChildWnd 类派生而来。如果应用程序不需要定制框架窗口,则也可以直接使用CFrameWnd类和 CMDIChildWnd类。
![Page 14: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/14.jpg)
MFC除了提供了 CDocTemplate抽象基类之外,还提供了CDocTemplate 的两个派生类: CSingleDocTemplate 和CMultiDocTemplate。
CSingleDocTemplate 类定义了一个实现单文档界面的文档模板。 SDI应用程序使用主框架窗口来显示一个文档,每次只能打开一个文档。
CMultiDocTemplate类定义了一个实现多文档界面的文档模板。MDI应用程序用主框架窗口作为工作空间,在其中可以打开单个或多个文档框架窗口。在每个文档窗口中显示一个文档。
![Page 15: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/15.jpg)
( 2)文档模板的创建 在初始化应用程序时,必须首先注册文档模板,以便程序利用这个模板来完成主框架窗口、视图、文档对象的创建和资源的装入。
在 SDI或MDI应用程序中,要注册文档模板,需通过 new运 算 符 调 用 文 档 模 板 类 的 构 造 函 数 生 成 一 个CSingleDocTemplate 或 CMultiDocTemplate 类对象,并调用函数 AddDocTemplate注册该文档模板对象。
![Page 16: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/16.jpg)
创建
创建 创建 创建
在函数 InitInstance 中创建
应用程序对象 文档模板对象
文档对象 框架窗口对象 视图对象
图 3.4 应用程序中各对象之间的创建关系
![Page 17: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/17.jpg)
图 3.5 应用程序中各对象之间的访问方法
通 过 GetFirstViewPosition
和
GetNextView 访问
通过 GetDocTemplate 访问
通过 GetActiveDocument 访问
通过函数 GetActiveView 访问
框架窗口对象
文档对象
视图对象
文档模板对象
通过 CWnd::GetParentFrame 访问
通过 GetDocument 访问
![Page 18: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/18.jpg)
3.2 菜单设计
![Page 19: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/19.jpg)
菜单分为两类 :
一类是依附于框架窗口的一般菜单,包括主菜单和子菜单,主菜单(菜单栏)横放在窗口的顶部,它是应用程序的最高层菜单,子菜单是从主菜单下弹出的菜单。
另一类是弹出式菜单,也叫快捷菜单或上下文菜单,它是点击鼠标右键后,在光标所在位置出现的浮动式自由菜单。
![Page 20: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/20.jpg)
3.2.1 建立菜单资源 菜单是Windows应用程序中一个必不可少的用户界面资源,
Visual C++ 2005集成开发环境提供了一个可视化菜单编辑器用于菜单的编辑和添加。
菜单中的每一个菜单项都由菜单项名(即 Caption)和命令ID号两个基本要素组成。
![Page 21: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/21.jpg)
创建菜单可以有好几种方法,最简单的方法是在属性窗口用菜单编辑器来进行设计。
利用菜单辑器创建菜单资源的主要步骤如下:
( 1)打开应用程序的菜单编辑器; ( 2)添加主菜单; ( 3)添加菜单项,设置菜单项的属性。
![Page 22: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/22.jpg)
【例 3.2】编写一个应用程序MyMenu,为程序添加一“ ” “ ” “个 图像 主菜单和它的两个下拉子菜单项 显示 和 删”除 。
程序的实现过程如下:
( 1)创建应用程序,打开菜单编辑器 ( 2)添加主菜单 ( 3)添加菜单项,设置菜单项的属性
![Page 23: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/23.jpg)
3.2.2 添加命令处理函数 Windows应用程序是通过消息传递机制运作的,菜单项对命令的激发、调用是通过发送WM_COMMAND消息实现的。
处理的原则是:依据菜单的不同作用进行不同的映射。
如果该菜单用于文档的显示编辑,则最好在视图类中映射。
如果该菜单用于文档的打开和存储,则最好在文档类中进行映射。
对于通用菜单,可以在框架类中映射。
![Page 24: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/24.jpg)
在【例 3.2】中只添加了菜单资源,并没有实现菜单的功能,即没有对应的命令处理函数与菜单项对应,因此,程序运行后添加的菜单项是灰色的,即处于当前不可用状态。添加新
的菜单项后,还应该为新的菜单项指定一个处理函数。
( 1)打开类视图找到相应的类。 ( 2 “ ”)单击其属性窗口中的 事件 按钮,此时属性窗口将列出此类可以处理的对象 ID。
( 3 “ ”)从 菜单命令 中选择 ID_SHOWPICTURE ,并单击其左侧“的 +”号,就会出现可处理的命令消息。
( 4)选择适当的消息,单击其右侧的单元格,就会出现提示信息
![Page 25: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/25.jpg)
快捷键的添加需要使用快捷键编辑器,添加快捷键的步骤如下:
( 1)打开应用程序的加速器表; ( 2)添加新的快捷键; ( 3)设置快捷键的属性。
![Page 26: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/26.jpg)
Visual C++ 2005的MFC提供的菜单类的对象可以用来表示各种Windows菜单,并且该类可以在程序运行时处理有关菜单的操作。
1. 创建菜单 CMenu类的成员函数 CreateMenu和 CreatePopupMenu 分别用来创建一个菜单或子菜单框架,它们的函数原型如下:
BOOL CreateMenu(); //产生一个空菜单 BOOL CreatePopupMenu(); //产生一个空的弹出式子菜单
2. 装入菜单 CMenu类的成员函数 LoadMenu可用来将菜单资源装入应用程序中,它的函数原型有两种 :
BOOL LoadMenu(LPCTSTR lpszResourceName); BOOL LoadMenu(UNIT nIDResource);
![Page 27: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/27.jpg)
3. 添加菜单项 当菜单创建后,可以调用 CMenu类提供的成员函数
AppendMenu或 InsertMenu 向菜单中添加一些菜单项 它们的函数原型如下: BOOL AppendMenu(UNIT nFlags, UNIT nIDNewItem,const
CBitmap * pBmp); BOOL AppendMenu(UNIT nFlags, UNIT nIDNewItem=0,LPCTSTR
lpszNewItem=NULL); BOOL InsertMenu(UNIT nPosition, UNIT nFlags, UNIT
nIDNewItem,const CBitmap *pBmp); BOOL InsertMenu(UNIT nPosition, UNIT nFlags, UNIT
nIDNewItem=0,LPCTSTR lpszNewItem=NULL); BOOL InsertMenuItem(UINT uItem, LPMENUITEMINFO
lpMenuItemInfo,BOOL fByPos = FALSE);
![Page 28: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/28.jpg)
4.删除菜单项 当要删除指定的菜单项时,可利用 CMenu类的成员函数 DeleteMenu来完成,该函数的原型为:
BOOL DeleteMenu(UNIT nPosition,UNIT nFlags);
5.获取菜单项 可以利用 CMenu类的以下 3个成员函数分别获得菜单的项数、菜单项的 ID号以及弹出式子菜单的句柄。
GetMenuItemCount()函数 GetMenuItemID()函数 GetSubMenu()函数
![Page 29: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/29.jpg)
3.2.3 弹出式菜单 弹出式菜单是通过利用 CMenu类和其成员函数,在程序运行过程中动态建立的。弹出式菜单的建立方法有两种:
( 1)利用现有的菜单项进行创建。
( 2)为弹出式菜单专门建立一个菜单资源,通过调用函数 CMenu::LoadMenu装入创建的菜单资源。
![Page 30: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/30.jpg)
弹出式菜单的实现过程如下:
( 1)利用成员函数 CMenu::CreatePopupMenu创建一个弹出式菜单。
( 2)利用成员函数 CMenu::LoadMenu装入菜单资源或利用成员函数 CMenu::AppendMenu添加菜单项。
( 3)利用成员函数 CMenu::TrackPopupMenu在指定位置显示弹出式菜单,并跟踪用户的菜单项选择。 TrackPopupMenu成员函数的原型为:
BOOL TrackPopupMenu (UNIT nFlags, int x, int y, CWnd *pWnd, LPCRECT lpRect=0);
![Page 31: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/31.jpg)
【例 3.6】为【例 3.5】的程序MyMenu “ ”的 图像 菜单添加弹出式菜单。编译运行该程序,单击鼠标右键并松开后得到如图 3.12所示的结果。
图 3.12 弹出式菜单
![Page 32: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/32.jpg)
程序的实现过程如下:
( 1)打开【例 3.5】的例子,在 Visual C++ 2005 “中,选择 文” “ ” “件 菜单中的 打开 菜单项下的 项目 / ”解决方案 ,打开上例中的
“ MyMenu.sln”文件。
( 2)在类视图中选择类CMyMenuView “,在属性窗口单击 消”息 按钮,选择WM_CONTEXTMENU,单击右侧下拉菜单中的
“ <添加 >OnContextMenu”选项,就在视图类 CMyMenuView中添加了消息WM_CONTEXTMENU的消息映射函数。
![Page 33: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/33.jpg)
3.3 工具栏和状态栏设计
![Page 34: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/34.jpg)
工具栏和状态栏是Windows系统中常用的两种界面元素。
一般情况下,在创建应用程序框架时,MFC自动为应用程序提供了一个标准工具栏和一个标准状态栏。
![Page 35: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/35.jpg)
3.3.1 添加工具栏
工具栏是一系列工具按钮的组合,也是一种常用的命令输入方式,用户可以用鼠标单击工具栏上的工具按钮来向应用程序发出命令。
MFC工具栏还支持工具提示 (Tooltip),工具提示用于帮助用户理解单个工具栏按钮的作用。
工具栏也是资源,在 Visual C++ 2005中创建工具栏资源 。
![Page 36: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/36.jpg)
1.创建工具栏资源
创建工具栏资源的步骤如下: ( 1)打开应用程序的工具栏编辑器; ( 2)添加工具栏按钮; ( 3)设置工具栏按钮属性。
![Page 37: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/37.jpg)
【例 3.7】为【例 3.6】的程序MyMenu “ ”的 图像 菜单项添加工具栏按钮。程序运行后,工具栏的实际效果如图 3.13所示,新添加的工具栏按钮位于工具栏的最后两个位置。
图 3.13 MyMenu 的工具栏
![Page 38: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/38.jpg)
程序的实现过程如下:
( 1)打开【例 3.6】的例子,在 Visual C++ 2005中,选择“ ” “ ” “文件 菜单中的 打开 菜单项下的 项目 / ”解决方案 ,打开上
“例中的 MyMenu.sln”文件。
( 2 “ ” “)在 资源视图 中展开 Toolbar”,双击其下的IDR_MAINFRAME ,打开工具栏编辑器,屏幕上同时显示工具栏设计窗口。
( 3 )添加工具栏按钮。
( 4 )设置工具栏按钮属性。
![Page 39: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/39.jpg)
2.动态生成工具栏
动态生成工具栏的方法如下: ( 1)声明一个 CToolBar类对象。 ( 2 ) 调 用 函 数 CToolBar::Create 或
CToolBar::CreateEx 生 成 指 定 风 格 的 工 具 栏 并 与CToolBar类对象相连接。
( 3)调用函数 CToolBar::LoadToolBar装入工具栏。
![Page 40: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/40.jpg)
【例 3.8】为【例 3.6】的程序MyMenu动态生成工具栏,程序的实际运行效果如图 3.18所示。
图 3.18 动态生成程序 MyMenu 的工具栏
![Page 41: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/41.jpg)
程序的实现过程如下:
( 1)打开【例 3.6】的例子,在 Visual C++ 2005中,选“ ” “ ” “择 文件 菜单中的 打开 菜单项下的 项目 / ”解决方案 ,
“打开上例中的 MyMenu.sln”文件。
( 2)添加一个工具栏资源。
( 3)如【例 3.7】的方法设置工具栏按钮的属性。
( 4)加载工具栏资源。
![Page 42: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/42.jpg)
3.3.2 定制状态栏
MFC提供另一种经常与输入命令相关的用户界面对象:状态栏。
状态栏是典型的位于应用程序主窗口底部的窗口,经常在状态栏显示文本提示信息。
![Page 43: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/43.jpg)
MFC把状态栏封装在状态栏类 CStatusBar中,动态创建状态栏的过程如下:
( 1)构造一个 CStatusBar类对象。 ( 2)调用 Create函数创建一个状态栏窗口,并将
该窗口连接到该 CStatusBar 类对象上。 ( 3)调用 SetIndicators函数设置指示器 ID。
![Page 44: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/44.jpg)
利用向导创建应用程序时,在 CMainFrame类中定义了一个成员变量 m_wndStatusBar ,它是状态栏类 CStatusBar的对象。在MFC应用程序框架的实现文件MainFrm.cpp中,为状态栏定义了一个静态数组 indicators,如下所示:
static UINT indicators[] ={//定义分隔符,作为提示信息行的面板标志
ID_SEPARATOR, ID_INDICATOR_CAPS, //大写指示器面板标志ID_INDICATOR_NUM, //数字指示器面板标志ID_INDICATOR_SCRL, //滚动指示器面板标志
};
![Page 45: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/45.jpg)
创建状态栏资源的具体步骤如下:
( 1)打开应用程序的串表编辑器; ( 2)添加新的串表,设置其属性; ( 3)添加指示器面板。
![Page 46: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/46.jpg)
【例 3.9】修改【例 3.7】的程序MyMenu,在状态栏上显示鼠标的位置,以及当前的状态(是显示图片还是删除图片)。程序的实际运行效果如图 3.19所示。
图 3.19 MyMenu 的状态栏
![Page 47: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/47.jpg)
程序的实现过程如下:
( 1)打开【例 3.7】的例子,在 Visual C++ 2005中,选“ ” “ ” “择 文件 菜单中的 打开 菜单项下的 项目 / ”解决方案 ,
“打开上例中的 MyMenu.sln”文件。 ( 2)添加串表。 ( 3)添加指示器面板。 ( 4)添加消息映射函数 OnMouseMove。 ( 5)修改 OnDraw函数,添加显示当前状态的代码。
![Page 48: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/48.jpg)
3.4 文档的读写
![Page 49: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/49.jpg)
用户处理的数据往往需要存盘做永久备份,在MFC应用程序中提供了数据序列化 (serialize)的方式来处理文档的读写功能。
序列化指的是从一个持久性存储介质读出或者写入一个对象的过程。
![Page 50: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/50.jpg)
3.4.1 序列化工作原理
文档类存盘的重点在于存储文档类中的成员变量,使之可以利用这些变量完成重建,而不损失任何信息。
同时文档还需要能够从存储的文档文件中读取信息以便重建文档类。
![Page 51: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/51.jpg)
序列化的基本思想是:
一个类应该能够对自己的成员变量的数据进行读写操作,对象可以通过读操作而重新创建。
由于 CObject类提供了保存和加载对象状态的基本功能,所以一般类的对象都具备将状态值写入磁盘或从磁盘中读出的方法,这种对象的保存和恢复的过程称为序列化。
![Page 52: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/52.jpg)
一个可序列化的类必须有一个称作为序列化的成员函数 Serialize,文档的序列化在文档类的成员函数 Serialize中进行。MFC应用程序向导在生成应用程序框架时只创建了文档派生类序列化函数 Serialize的框架,如下所示:
void CMyDoc::Serialize(CArchive& ar){
if (ar.IsStoring()){
// TODO: 在此添加存储代码}else{
// TODO: 在此添加加载代码}
}
![Page 53: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/53.jpg)
程序员要做的就是重载文档类的 Serialize,并在函数中加入读和写的代码。
C++主要通过文件句柄来实现磁盘输入和输出,一个文件句柄与一个磁盘文件相关联。
文件数据的序列化归根到底是类的序列化,可序列化的类必须直接或间接从类 CObject派生,在类的头文件中,还必须包含 DECLARE_SERIAL宏调用,在类的实现文件中必须包含 IMPLEMENT_SERIAL宏调用。
![Page 54: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/54.jpg)
3.4.2 MFC 应用程序的序列化
MFC应用程序实现类的序列化通常需要以下几个步骤:1.可序列化类从 CObject类或者 CObject类的派生类派生;2.重载 CObject类的成员函数 Serialize();3.在类声明中使用 DECLARE_SERIAL宏;4.定义一个无参数的构造函数;5.在类实现文件中使用 IMPLEMENT_SERIAL宏。
![Page 55: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/55.jpg)
【例 3.10】编写一个应用程序MyDrawLine,程序运行后,当用户在客户区窗口按下鼠标左键并移动时,根据鼠标移动的轨迹绘制指定的线段。并且能将绘制好的图形保存在磁盘上。程序的实际效果如图 3.20所示。
图 3.20 程序 MyDrawLine 的绘制线段效果
![Page 56: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/56.jpg)
程序的实现过程如下: ( 1)创建应用程序 利用 MFC 应用程序向导创建一个 SDI 应用程序
MyDrawLine。 ( 2)实现绘制线段功能 ① 为矩形定义一个新类 Cline。 ② 在视图类的头文件中定义两个公有变量,在视图类的
构造函数中初始化这两个公有变量,分别记录线段的起点和终点:
③ 在 视 图 类 中 为WM_LBUTTONDOWN 、 WM_MOUSEMOVE 和WM_LBUTTONUP 消息分别添加消息映射函数OnLButtonDown、 OnMouseMove和 OnLButtonUp。
![Page 57: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/57.jpg)
( 3)文档数据系列化
① 在 CLine类的头文件中加入以下代码: ② 在 CLine类的实现文件中加入 Serialize函数的代码: ③ 在文档类 CMyDrawLineDoc的头文件中加入下面的代码:
④ 在文档类 CMyDrawLineDoc的 Serialize函数中加入代码。
![Page 58: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/58.jpg)
( 4)在视图类的 OnDraw函数中加入下面的代码,其中粗体部分为新添加的代码。
( 5)修改视图类的 OnLButtonUp函数。
( 6)设置文档类型。
![Page 59: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/59.jpg)
3.5 使用不同视图
![Page 60: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/60.jpg)
MFC为应用程序提供了多种不同的视图,在利用MFC 应用程序向导创建应用程序时可以选择不同的视图。
表 3.11 视类及其说明
视类 说明CView 最基本的视类,其他视类都有它派生而来CScrollView 带滚动条的视类CCtrlView 基本视
类, CListView 、 CTreeView 、 CEditView 和 CRichEditView 都由它派生而来
CListView 显示列表控件的视类CTreeView 显示树形控件的视类CFormView 使用对话框资源显示一个格式化窗口的视类CEditView 提供基本文本编辑功能的视类CRecordView 能显示数据库记录的视类CRichEditView
通过使用 RichEdit 控件提供复杂编辑功能的视类
CDaoRecordView
能显示 DAO 数据库记录的视类
![Page 61: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/61.jpg)
3.5.1 滚动视图 为了实现滚动视图, MFC 提供了一个滚动视图类
CScrollView,该类中常用的成员函数
表 3.12 滚动视图类 CscrollView 的常用成员函数
成员函数 说明GetTotalSize 获取滚动视图的大小GetScrollPosition
获取当前可见视图左上角的坐标
SetScrollSizes
设置整个滚动视图的大小、每一页和每一行的大小
![Page 62: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/62.jpg)
创建应用程序时一般采用视图类 CView作为视图的基类,如果增加滚动功能,可直接在原来的程序基础上进行修改:
( 1)手工将视图类 CView改为 CScrollView。 ( 2 ) 重 载 视 图 类 虚 函 数 OnInitialUpdate 或
WM_CREATE的消息处理函数 OnCreate。 ( 3)注意设备坐标与逻辑坐标的转换。
![Page 63: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/63.jpg)
【例 3.11】为程序MyDrawLine增加滚动视图的功能。
程序的实现过程如下:
( 1 ) 将 文 件 MyDrawLineView.h 和MyDrawLineView.cpp 中所有的 CView 字符串替换为CScrollView字符串。
( 2)在类视图中选择类 CMyDrawLineView,单击鼠“ ” “标右键,在弹出的快捷菜单中选择 添加 菜单项下的 添
” “ ”加函数 ,弹出 添加成员函数向导 对话框。
![Page 64: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/64.jpg)
( 3)程序使用的坐标系是MM_TEXT映射模式,原点为工作区左上角,向右和向下分别为 X轴和 Y轴的正方向
① 在视图类中定义公有变量 ptOrg,用来记录当前视图的原点坐标
② 修改 OnLButtonDown函数,获取当前视图的原点坐标
③ 修改 OnLButtonUp函数,更改起点和终点坐标
![Page 65: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/65.jpg)
3.5.2 多视图 文档与视图分离使得一个文档对象可以和多个视图相关联,这样可以更容易的实现多视图的应用程序。
1.MDI程序的多视图 MFC实现多视图的基本方法如下:
( 1)利用类向导建立新的视图类; ( 2)在函数 InitInstance中创建一个与新的视图类相关联的文档模板对象;在函数 ExitInstance中删除创建的文档模板对象,但暂时不加入它;
( 3 ) 在 相 关 菜 单 的 命 令 处 理 函 数 中 调 用 函 数CDocTemplate::CreateNewFrame 为创建的文档模板创建新的框架窗口,调用函数 CDocTemplate::InitalUpdateFrame 更新视图。
![Page 66: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/66.jpg)
2. SDI程序的多视图
在 SDI 程序中可以采用拆分窗口的方式实现多视图。
拆分窗口主要是通过类 CSpitterWnd 来实现的。
![Page 67: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/67.jpg)
【例 3.13】对【例 3.11】进行修改,采用拆分窗口的方法在单文档应用程序中实现多视图的功能。该程序的功能同【例 3.12】,程序运行的实际效果如图 3.25所示。
图 3.25 单文档应用程序中的多视图
![Page 68: 第 3 章 文档和视图](https://reader030.fdocuments.net/reader030/viewer/2022012818/56813f53550346895daa1500/html5/thumbnails/68.jpg)
程序的实现过程如下:
( 1)在类视图重生成一个新的视图类 CPositionView,其基类为 CScrollView。重写 CPositionView类OnInitialUpdate函数
( 2)拆分窗口 ① 在框架类 CMainFrame的头文件添加共有成员变量 ② 在框架类 CMainFrame中添加虚函数OnCreateClient,在该函数中完成拆分窗口的功能
( 3)在类 CPositionView的OnDraw函数中添加显示文本的语句