友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
VC语言6.0程序设计从入门到精通-第28部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
oldBrush = dc。SelectObject(&newBrush);
// 用像素颜色的填充颜色矩形
dc。Rectangle(clrRect);
dc。SelectObject(oldBrush);
newBrush。DeleteObject();
// 刷新屏幕
Invalidate(FALSE);
}
CDialog::OnLButtonDown(nFlags; point);
}
·174 ·
…………………………………………………………Page 184……………………………………………………………
第 7 章 图形图像
3 .运行结果
程序运行后,用鼠标单击图片不同的区域,程序界面如图 7…7 所示。
(a ) (b )
图 7…8 4 鼠标点在不同区域的颜色
7。5 本章小结
本章讲述了使用 Visual C++进行图形绘制和图像处理的基本方法 。介绍了 Windows 基本
的绘图函数,主要的 GDI 对象,并且给出相应的实例 。给一个图像浏览器应用程序,介绍了
图像处理的基本知识和算法。通过对本章的阅读,读者应该了解图形绘制和图像处理的基本
原理和方法。此外,本章还给出了一些相关的小技巧。
·175 ·
…………………………………………………………Page 185……………………………………………………………
第 8 章 文件操作
第 8 章 文件操作
文件操作是操作系统提供的基本功能之一。本章将通过示例介绍在 MFC 中对文件进行
CFile 文件操作和文件对话框 3 部分内容。这 3 部分基本涵盖
操作的方法,主要包括串行化、
了 MFC 中对文件的主要操作。同时还详细地介绍各种文件操作函数的使用方法,为读者编
写功能复杂的文件处理程序提供参考。
8。1 串行化基础知识
在 Visual C++ 中使用 MFC 开发的基于文档的应用程序 。在这个框架中,数据的维护及其
显示分别由两个不同,但又彼此紧密相关的对象—文档和视图实现的。MFC 中各种自动化
代码的存在,文档视图结构在很多场合与传统的编程方式相比更有利于应用程序的编写。串
行化就是这样一个自动化过程,它使得对文档的磁盘读写操作变得简单易行。本节将详细介
绍串行化的基础知识,包括文档的基本结构、用 Serialize()函数实现串行化、与串行化相关的
类,以及在文档视图中添加串行化代码 4 个部分。
8。1。1 文档类
在文档视图结构中,文档的任务通常是对数据进行管理和维护。数据一般都被保存在文
档类的成员变量中 。而在 MFC 中,文档类通过一个称为串行化(Serialize )的过程将数据保
存到磁盘文件中或者将数据从磁盘文件中读取。文档类为数据的串行化提供了默认的支持,
并将其作为可重载函数,只需重载这些成员函数就可以为程序提供自定义的串行化支持。
文档类在文档视图结构中主要完成以下几个任务。
o 在内存中保存应用程序特定的数据,并对其进行管理,同时提供给视图类进行显示。
o 提供用于操作文档数据的接口。
o 参与写文件和读文件。通过串行化功能,文档类可以将数据从文件中读出或者写入。
o 参与打印输出。这个任务主要通过视图类访问文档进行。
o 处理跟文档有关的命令消息。这些命令包括菜单项、工具栏按钮或快捷键生成的命令。
默认情况下,文档类使用序列化处理“文件”菜单的“保存”和“另存为”命令。还
可以为其他跟文档相关的自定义命令添加相应的处理函数。
为了完成上述的任务,文档类的基类 CDocument 提供了下列一些成员函数。
1.处理文档数据与文件相关的操作的函数
(1)GetTitle()和 SetTitle()
这两个函数作为一组,前者用于获取文档的标题,后者用于设置文档标题。原型为:
…………………………………………………………Page 186……………………………………………………………
第 8 章 文件操作
const CString& GetTitle( ) const;
virtual void SetTitle(
LPCTSTR lpszTitle
);
(2 )GetPathName()和 SetPathName()
这两个函数用于处理文档保存的路径 。前者用于获得文档保存路径的字符串,后者设置
该路径。原型为:
const CString& GetPathName( ) const;
virtual void SetPathName(
LPCTSTR lpszPathName;
BOOL bAddToMRU = TRUE
);
参数 bAddToMRU 用于确定是否将路径添加到最近打开的文档列表中。
2 .GetDocTemplate()
该函数用于获得文档模板对象的指针。原型为:
CDocTemplate* GetDocTemplate( ) const;
3 .处理文档类和视图类的关系的函数
(1)AddView()
该函数用于向与文档相关联的视图列表中添加指定的视图。原型为:
void AddView(
CView* pView
);
参数 pView 指向需要添加的视图对象。
(2 )RemoveView()
该函数用于从文档类的视图列表中删除指定视图。原型为:
void RemoveView(
CView* pView
);
参数 pView 指向需要删除的视图对象。
(3 )UpdateAllView()
该函数用于通知所有视图进行重绘。一般情况下,当文档数据被修改后,应当调用这个
函数使得所有跟文档关联的视图进行重绘,以显示最新的内容。原型为:
void UpdateAllViews(
CView* pSender;
LPARAM lHint = 0L;
CObject* pHint = NULL
);
·175 ·
…………………………………………………………Page 187……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
o 参数 pSender :用于指定修改文档的视图类的指针。
o 参数 lHint 和 pHint :存有修改的一些参数。
4 .虚函数
下面介绍的函数是 CDocument 类提供的虚函数,程序的 CDocument 派生类通过重载这
些函数提供程序自定义的功能。
(1)OnNewDocument()
该虚函数用于在建立文档时被 MFC 框架调用。原型为:
virtual BOOL OnNewDocument( );
o 函数返回值:函数是否成功的标志。
(2 )OnOpenDocument ()
该虚函数用于在打开文档时被 MFC 框架调用。原型为:
virtual BOOL OnOpenDocument(
LPCTSTR lpszPathName
);
o 参数 lpszPathName :用于获得将要打开文档的路径。
o 函数返回值:函数是否成功的标志。
(3 )OnSaveDocument ()
该虚函数用于在保存文档时被 MFC 框架调用。原型为:
virtual BOOL OnSaveDocument(
LPCTSTR lpszPathName
);
o 参数 lpszPathName :用于获得将要保存文档的路径。
o 函数返回值:函数是否成功的标志。
(4 )OnCloseDocument()
该虚函数用于在关闭文档时被 MFC 框架调用。原型为:
virtual void OnCloseDocument( );
(5 )CanCloseFrame()
该虚函数用于确认文档的框架窗口是否允许被关闭,比如文档未保存时,在框架窗口要
被关闭时提示是否保存文档。原型为:
virtual BOOL CanCloseFrame(
CFrameWnd* pFrame
);
o 参数 pFrame :该文档的框架窗口类的指针。
o 函数返回值:函数是否成功的标志。
(6 )DeleteContents()
该虚函数用于在未销毁文档对象时删除文档数据。原型为:
virtual void DeleteContents( );
·176 ·
…………………………………………………………Page 188……………………………………………………………
第 8 章 文件操作
(7 )ReleaseFile()
该虚函数用于释放文件以允许其他应用程序使用。原型为:
virtual void ReleaseFile(
CFile* pFile;
BOOL bAbort
);
o 参数 pFile :要释放的 CFile 对象。
o 参数 bAbort :指定用什么方法释放对象,若取值为 TRUE,则用 CFile::Abort(),反之
用 CFile::Close() 。
(8)SaveModified()
该虚函数用于查询文档的修改状态并存储修改的文档。原型为:
virtual BOOL SaveModified( );
o 函数返回值:函数是否成功的标志。
8。1。2 Serialize()函数
在 8。1。1 节中介绍了文档的主要结构,本小节将讲述如何创建和使用文档与磁盘文件之
间的串行化读写通道,即 Serialize()函数。
1.串行化的基本概念
串行化在面向对象程序设计领域中的基本概念是指对象可以被持续,即当程序退出时,
它们可以被保存在磁盘中,而当程序重新运行时又可以从磁盘中读取恢复。对象的这种保存
和恢复的过程就称为“串行化 ”。在 MFC 中,对象串行化的成员函数称为 Serialize()成员函
数。这个函数提供了将类的数据进行存盘和读取的功能。
在 MFC 中,串行化过程是顺序的,即与文档相关的所有对象只能在某个单独的文件中
MFC 的文档类中就只提供了顺序保存和读写
进行顺序的读或写,而并不能进行随机的访问。
文档数据的功能。
2 .将类串行化
将类串行化需要进行下列几个步骤:
(1)从 CObject 派生
在 CObject 类中定义了基本的序列化协议和功能,需要串行化的类必须直接或间接地从
CObject 类派生,从而获得对 CObject 的序列化协议及功能的访问权限。
(2 )添加 DECLARE_SERIAL()宏
设置好基类后,在类的声明中添加一个 DECLARE_SERIAL()宏,具体代码如下:
class CSample : public CObject // 由 CObject 派生
{
public:
……//其他成员变量和成员函数的定义
·177 ·
…………………………………………………………Page 189……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
DECLARE_SERIAL(CSample) //声明串行化,参数为该类的类名
……//其他成员变量和成员函数的定义
};
(3 )添加 IMPLEMENT_SERIAL()宏
在类的实现文件中添加 IMPLEMENT_SERIAL()宏,具体代码如下:
IMPLEMENT_SERIAL(CSample; CObject; 0) //该宏一般应包含在 Sample。cpp 文件中
IMPLEMENT_SERIAL()宏用于定义从 CObject 中派生可序列化类时所需的各种函数。在
类的实现文件(。CPP) 中使用这个宏。该宏的前两个参数是类名和直接基类的名称。
该宏的第三个参数是架构编号。架构编号实质上是类对象的版本号,它使用大于或等于
零的整数。MFC 序列化代码在将对象读取到内存时检查该架构编号 。如果磁盘上对象的架构
编号与内存中类的架构编号不匹配,库将引发 CArchiveException 防止程序读取对象的不正确
版本。
(4 )定义不带参数的构造函数
对象从磁盘上加载后, MFC 通过 CreateObject() 函数自动重新创建这些对象。而
CreateObject()函数创建对象时需要一个默认的构造函数。可将该构造函数声明为公共的、受
保护的或私有的。在此之前,请确保它仅由串行化函数使用。
3 .编写 Serialize()函数
在 CObject 类中定义的 Serialize()成员函数,实际上是对捕获对象的当前状态所必需的数
据进行串行化 。因此在为类做好串行化的准备后,再为类重载 CObject 的 Serialize()成员函数,
就可以实现串行化的功能。例如 CSampleData 类中有如下的成员变量:
public:
CString m_strName;
int m_nType;
实现 CSampleData 的序列化,就需要将这两个成员变量保存到磁盘中或者从磁盘中装入,
于是将 CSampleData::Serialize()函数代码修改为:
void CSampleData::Serialize(CArchive& ar)
{
CObject::Serialize(ar); //进行基类的序列化
if (ar。IsStoring()) {
ar m_strName 》》 m_nType; //读取数据
}
}
在上面的代码中,首先调用基类的 Serialize()函数进行基类的序列化,保证保存和装入的
数据的正确性。
Serialize()函数具有 CArchive 参数 ar 的特性,即读写对象数据。CArchive 对象中包括成
·178 ·
…………………………………………………………Page 190……………………………………………………………
第 8 章 文件操作
员函数 IsStoring(),该成员函数返回值为 TRUE 时表示 Serialize()正在存储(即正在写入数据 ),
反之则表明正在加载(即正在读取数据 )。用 IsStoring() 的结果作为参考,使用输出运算符(》 )提取数据。这也反映了 MFC 串
行化的顺序性,即不能进行随机的读写操作,一次调用只能读取或只能保存。
在串行化代码中需要对各种数据类型进行处理,主要分为下列几种情况。
(1)固有数据类型
CArchive 类的插入运算符(》 )对许多 C++ 固有的数据类型进行了
重载,可以直接使用。例如在上面的程序中要对 int 的成员变量 m_nType 进行串行化,即可
直接使用插入运算符和提取运算符。下面列出一些被 CArchive 类默认支持的数据类型:
o BYTE :8 位无符号整数。
o WORD :16 位无符号整数。
o LONG :32 位带符号整数。
o DWORD :32 位无符号整数。
o float:单精度浮点数。
o double :双精度浮点数。
o int :32 位带符号整数。
o short:16 位带符号整数。
o char :8 位字符类型。
o unsigned :32 位无符号整数。
(2 )CString 和 CRect 等类型
CString 和 CRect 等类型,虽然不是从 CObject 派生的类,但是它们有自己针对 CArchive
类的重载插入运算符和提取运算符,因此也可以直接使用这两个运算符进行串行化。
(3 )自定义的类
如果序列化的类中包含其他自定义的内嵌对象,则需要处理后再进行串性化。例如在
CSampleData 类中添加如下的新数据成员:
public:
CSampleChildData m_data;
将 CSampleData 类串行化时,需要对 CSampleChildData 进行额外的处理。首先使得
CSampleChildData 继承 CObject,然后编写它自己的 Serialize()成员函数。这时 CSampleData
类的 Serialize()函数可以进行如下修改以实现对 m_data 的串行化:
void CSampleData::Serialize(CArchive& ar)
{
CObject::Serialize(ar); //进行基类的序列化
if (ar。IsStoring()) {
ar m_strName 》》 m_nType; //读取数据
}
·179 ·
…………………………………………………………Page 191……………………………………………………………
Visual C++ 6。0 程序设计从入门到精通
m_Data。Serialize(ar); // 串行化 m_Data
}
如果 CSampleData 类中的 CSampleChildData 对象是通过指针在堆中创建的,则代码如下:
public:
CSampleChildData *m_pData;
将 CSampleData 类串行化更为简单。首先需要为 CSampleChildData 添加串行化代码,即
继承 CObject,并添加相应的宏和构造函数,最后编写 CSampleChildData 自己的 Serialize()
函数。完成对 CSampleChildData 的修改后就可以在 CSampleData 类的 Serialize()函数中用
CArchive 的插入和提取运算符进行串行化。代码如下:
void CSampleData::Serialize(CArchive& ar)
{
CObject::Serialize(ar); //进行基类的序列化
if (ar。IsStoring()) {
ar 》
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!