《[高等教育]第5章 框架窗口、文档和视图2.doc》由会员分享,可在线阅读,更多相关《[高等教育]第5章 框架窗口、文档和视图2.doc(42页珍藏版)》请在三一办公上搜索。
1、5.3文档序列化用户处理的数据往往需要永久存盘作永久备份。将文档类中的数据成员变量的值保存在磁盘文件中,或者将存储的文档文件中的数据读取到相应的成员变量中。这个过程称为序列化(Serialize)。5.3.1文档序列化过程MFC文档序列化过程包括:创建空文档、打开文档、保存文档和关闭文档这几个操作,下面来阐述它们的具体运行过程。1. 创建空文档应用程序类的InitInstance函数在调用了AddDocTemplate函数之后,会通过CWinApp:ProcessShellCommand间接调用CWinApp的另一个非常有用的成员函数OnFileNew,并依次完成下列工作:(1)构造文档对象,
2、但并不从磁盘中读数据。(2)构造主框架类CMainFrame的对象,并创建该主框架窗口,但不显示。(3)构造视图对象,并创建视图窗口,也不显示。(4)通过内部机制,使文档、主框架和视图“对象”之间“真正”建立联系。注意与AddDocTemplate函数的区别,AddDocTemplate函数建立的是“类”之间的联系。(5)调用文档对象的CDocument:OnNewDocument虚函数,并调用CDocument:DeleteContents虚函数来清除文档对象内容。(6)调用视图对象的CView:OnInitialUpdate虚函数对视图进行初始化操作。(7)调用框架对象的CFrameWnd
3、:ActiveFrame虚函数,以便显示出带有菜单、工具栏、状态栏以及视图窗口的主框架窗口。在单文档应用程序中,文档、主框架以及视图对象仅被创建一次,并且这些对象在整个运行过程中都有效。CWinApp:OnFileNew函数被InitInstance函数所调用。但当用户选择“文件”(File)菜单中的“新建”(New)时,CWinApp:OnFileNew也会被调用,但与InitInstance不同的是,这种情况下不再创建文档、主框架以及视图对象,但上述过程的最后三个步骤仍然会被执行。2. 打开文档当MFC AppWizard(exe)创建应用程序时,它会自动将“文件”菜单中的“打开”(Ope
4、n)的命令(ID号为ID_FILE_OPEN)映射到CWinApp的OnFileNew成员函数。这一结果可以从应用类(.cpp)的消息入口处得到验证:BEGIN_MESSAGE_MAP(CEx_SDIApp,CWinApp)ON_COMMAND(ID_FILE_NEW,CWinApp:OnFileNew)ON_COMMAND(ID_FILE_OPEN,CWinApp:OnFileOPEN)/Standard print setup commandON_COMMAND(ID_FILE_PRINT_SETUP,CWinApp:OnFilePrintSetup)END_MESSAGE_MAP()On
5、FileOpen函数还会进一步完成下列工作:(1)弹出通用文件“打开”对话框,供用户选择一个文档。(2)文档指定后,调用文档对象的CDocument:OnOpenDocument虚函数。该函数将打开文档,并调用DeleteContents清除文档对象的内容,然后创建一个CArchive对象用于数据的读取,接着又自动调用Serialize函数。(3)调用视图对象的CView:OnInitialUpdate虚函数。除了使用“文件|打开”菜单命令外,用户也可以通过选择最近使用过的文件列表来打开相应的文档。在应用程序的运行过程中,系统会及录下4个默认最近使用过的文件,并将文件名保存在Windows的注
6、册表中。当每次启动应用程序时,应用程序都会将最近使用过的文件名显示在“文件”菜单中。3.保存文档当MFC AppWizard(exe)创建应用程序时,它会自动将“文件”菜单中的“保存”(Save)命令与文档类CDocument的OnFileSave函数在内部关联起来,但用户在程序框架中看到相应的代码。OnFileSave函数还会进一步完成下列工作:(1)弹出通用文件“保存”对话框,让用户提供一个文件名。(2)调用文档对象的CDocument:OnSaveDocument虚函数,接着又自动调用Serialize函数,将CArchive对象的内容保存在文档中。说明:l 只有在保存文档之前还没有存过
7、盘(即没有文件名)或读取的文档是“只读”的,OnFileSave函数才会弹出通用“保存”对话框。否则,只执行第二步。l “文件”菜单中还有一个“另存为”命令,它与文档类CDocument的OnFileSaveAs函数相关联。不管文档有没有保存过,OnFileSaveAs都会执行上述两个步骤。l 上述文档存盘的必要操作都是由系统自动完成的。4.关闭文档当用户试图关闭文档(或退出应用程序)时,应用程序会根据用户对文档的修改与否来进一步完成下列任务:若文档内容已被修改,则弹出一个消息对话框,询问用户是否需要将文档保存。当用户选择“是”,则应用程序指向OnFlieSave过程。调用CDocument:
8、OnCloseDocument虚函数,关闭所有与该文档相关联的文档窗口及相应的视图,调用文档类CDocument的DeleteContents清除文档数据。需要说明的是,MFC应用程序通过CDocument的protected类型成员变量m_bModified的逻辑值来判断用户是否对文档进行修改,如果m_bModified为“真”,则表示文档被修改。对于用户来说,可以通过CDocument的SetModifiedFlag成员函数来设置或通过IsModified成员函数来访问m_bModified的逻辑值。当文档创建、从磁盘中读出以及文档存盘时,文档的这个标记就被置为FALSE(假);而当文档数
9、据被修改时,用户必须使用SetModifiedFlag函数将该标记置为TURE(真)。这样,当关闭文档时,应用程序就会弹出消息对话框,询问是否保存已修改的文档。由于多文档应用程序序列化过程基本上和单文档相似,因此这里不再重复。5.3.2 CArchive类和序列化操作从上述的单文档序列化过程可以看出:打开和保存文档时,系统都会自动调用 Serialize函数。事实上,MFC AppWizard(exe)在创建文档应用程序框架时已在文档类中重载了Serialize函数,通过在该函数中添加代码可达到实现数据序列化的目的。例如,在Ex_SDI单文档应用程序的文档类中有这样的默认代码:void CEx
10、_SDIDoc:Serialize(CArchivea& ar)if(ar.IsStoring()/当文档数据需要存盘时/TODO:add storing code hereelse /当文档数据需要读取时 /TODO:add loading code here代码中,Serialize函数的参数ar是一个CArchive类引用变量。通过判断ar.IsStoring的结果是“真”还是“假”就可决定向文档写或读数据。CArchive(归档)类提供对文件数据进行缓存,它同时还保存一个内部标记,用来标识文档是存入(写盘)还是载入(读盘)。每次只能有一个活动的存档与ar相连。通过CArchive类可以
11、简化文件操作,它提供“”运算符,用于向文件写入简单的数据类型以及从文件中读取它们。表5.6列出了CArchive所支持的常用数据类型。表5.6 ar中可以使用运算符的数据类型类型描述类型描述BYTE8位无符号整型WORD16位无符号整型LONG32位带符号整型DWORD32位无符号整型float单精度浮点double双精度浮点int带符号整型short带符号短整型char字符型unsigned无符号整数除了“”运算符外,CArchive类还提供成员函数ReadString和WriteString用来从一个文件对象中读写一行文本,它们的原型如下:Bool ReadString(CString&
12、rString);LRTSTR ReadString(LPTSTR lpsz,UINT nMax);Void WriteString(LPCTSTR lpsz);其中,lpsz用来指定读或写的文本内容,nMax用来指定可以读出的最大字符个数。需要说明的是,当向一个文件写一行字符串时,字符“0”和“n”都不会写到文件中,在使用时要特别注意。下面举一个简单的示例来说明Serialize函数和CArchive类的文档序列化操作方法。(1)用MFC AppWizard(exe)创建一个默认的单文档应用程序Ex_SDIArchive。(2)将工作区切换到ResourceView选项卡,展开所有结点,打开
13、String Table资源,双击String Table,将文档模板字符串资源IDR_MAINFRAME内容Caption修改为:(3)为CEx_SDIArchiveDoc类添加下列成员变量:public: char m_chArchive100; /读写数据时使用CString m_strArchive; /读写数据时使用BOOL m_bIsMyDoc; /用于判断文档(4)在CEx_SDIArchiveDoc类构造函数中添加下列代码:CEx_SDIArchiveDoc:CEx_SDIArchiveDoc()m_bIsMyDoc=FALSE;(5)在CEx_SDIArchiveDoc:On
14、NewDocument函数中添加下列代码:BOOL CEx_SDIArchiveDoc:OnNewDocument()if(!CDocument:OnNewDocument()return FALSE;strcpy(m_chArchive,&这是一个用于测试文档的内容!);m_strArchive=这是一行文本!;m_bIsMyDoc=TRUE;return TRUE;(6)在CEx_SDIArchiveDoc:Serialize函数中添加下列代码:void CEx_SDIArchiveDoc:Serialize(CArchive& ar)if(ar.IsStoring()if(m_bIsMy
15、Doc)/是自己的文档for(int i=0;isizeof(m_chArchive);i+)arm_chArchive0; /读取文档首字符if(m_chArchive0=&) /是自己的文档for(int i=1;im_chArchivei;ar.ReadString(m_strArchive);CString str;str.Format(%s%s,m_chArchive,m_strArchive);AfxMessageBox(str);m_bIsMyDoc=TRUE;else /不是自己的文档 m_bIsMyDoc=FALSE; AfxMessageBox(打开的文档无效!);(7)编
16、译运行并测试。程序运行后,选择“文件|另存为”菜单命令,指定一个文档名1.my,然后选择“文件|打开”菜单命令,再打开该文档,结果就会弹出对话框,显示该文档的内容,其效果如下图所示。需要说明的是,Serialize函数对操作的文档均有效,为了避免对其他文档误操作,这里在文档中加入“&”字符来作为自定义文档的标识,以与其他文档相区别。5.3.3 建立可序列化的类使一个类可序列化的目的是使其具有CArchive的序列化功能,即可以在文档类中的Serialize函数中直接通过CArchive应用变量进行该类数据的读写操作。在MFC中,可序列化的类必须是CObject的一个派生类,且在类声明中,需要包
17、含DECLARE_SERIAL宏调用,而在类的实现文件中包含IMPLEMENT_SERIAL宏调用,这个宏有三个参数:前两个参数分别表示类名和基类名,第三个参数表示应用程序的版本号。最后还需要重载Serialize函数,使该类的数据成员进行相关序列化操作。下面为“学生基本信息”建立一个可序列化类CStudentInfo。需要说明的是,由于使用MFC ClassWizard无法添加一个CObject类的派生类,因此必须手动进行。(1)用MFC ClassWizard (exe)创建一个默认的单文档应用程序Ex_Student。(2) 选择“文件|新建”菜单命令,选择“文件”选项卡,在左边的列表框
18、中选择C/C+ Header File项,在右边的“文件”下的编辑框中输入StudentInfo.h,单击“确定”按钮。在文档窗口中输入下面的代码:class CStudentInfo:public CObjectCString strName; /姓名CString strNO; /学号BOOL bMale;/性别,是否为男CTime tBirth; /出生年月CString strSpecial; /专业DECLARE_SERIAL(CStudentInfo) /序列化声明public:CStudentInfo() ;CStudentInfo(CString name,CString id
19、,BOOL male,CTime birth,CString special);void Serialize(CArchive &ar);void Display(int y,CDC *pDC);/在坐标为(0,y)处显示数据;(3)再次选择“文件|新建”菜单命令,选择“文件”选项卡,在左边的列表框中选择Source File项,在右边的“文件”下的编辑框中输入StudentInfo.cpp,单击“确定”按钮。在文档窗口中输入下面的代码:#includestdafx.h#includeStudentInfo.hCStudentInfo:CStudentInfo(CString name,CSt
20、ring id,BOOL male,CTime birth,CString special)strName = name;strNO = id;bMale = male;tBirth = birth;strSpecial = special;void CStudentInfo:Display(int y,CDC *pDC)CString str,strSex(女);if(bMale)strSex=男;str.Format(%s %s %s %s %s,strName,strNO,strSex,tBirth.Format(%Y-%m-%d),strSpecial);pCD-TextOut(0,y
21、,str);IMPLENENT_SERIAL(CStudentInfo,CObject,1) /序列化实现void CStudentInfo:Serialize(CArchive &ar)if(ar.IsStoring()arstrNamestrNObMaletBirthstrNamestrNObMaletBirthstrSpecial;(4)编译。5.3.4 使用简单数组集合类上述文档的读写是通过变量来存取文档数据的,实际上还可以使用MFC提供的集合类来进行操作。这样不仅有利于优化数据结构,简化数据的序列化,而且还可以保证数据类型的安全性。集合类常常用于装载一组对象,组织文档中的数据,也常用
22、作数据的容器。从集合类的表现形式上看,MFC提供的集合类可分为三类:链表集合类(List)、数组集合类(Array)和映射集合类(Map)。限于篇幅,这里仅讨论简单的数组集合类,它包括CObArray(对象数组集合类)、CByteArray(BYTE数组集合类)、CDWordArray(DWORD数组集合类)、CPtrArray(指针数组集合类)、CStringArray(字符串数组集合类)、CUIntArray(UINT数组集合类)和CWordArray(WORD数组集合类)。简单数组集合类是一个大小动态可变的数组,数组中的元素可用下标运算符“”来访问(从0开始)、设置或获取元素数据。若要设
23、置超过数组当前个数的元素的值,可以指定是否使数组自动扩展。当数组不需扩展时,访问数组集合类的速度与访问标准C+中的数组的速度同样快。以下的基本操作对所有的简单数组集合类都适用。1. 简单数组集合类的构造及元素的添加对简单数组集合类构造的方法都是一样的,均是使用各自的构造函数,它们的原型如下:CByteArrayCByteArray();CDWordArrayCDWordArray();CObArrayCObArray();CPtrArrayCPtrArray();CStringArrayCStringArray();CUIntArrayCUIntArray();CWordArrayCWordA
24、rray();下面的代码说明了简单数组集合类的两种构造方法:CObArray array; /使用默认的内存块大小CObArray* pArray=new CObArray; /使用堆内存中的默认的内存块大小为了有效的使用内存,在使用简单数组集合类之前最好调用成员函数SetSize设置此数组的大小,与其对应的函数GetSize,用来返回数组的大小。它们的原型如下:Void SetSize(int nNewSize,int nGrowBy=-1);Int GetSize() const;其中,参数nNewSize用来指定新的元素的数目(必须大于或等于0)。nGrowBy表示当数组需要扩展时允许添
25、加的最少元素数目,默认时为自动扩展。向简单数组集合类添加一个元素,可使用成员函数Add和Append,它们的原型如下:Int Add(CObject* newElement);Int Append(const CObArray& src);其中,Add函数是向函数组的末尾添加一个新元素,且数组自动增1。如果调用的函数SetSize的参数nGrowBy的值大于1,那么扩展内存将被分配。此函数返回被添加的元素序号,元素序号就是数组下标。参数newElement表示要添加的相应类型的数据元素。而Append函数是向数组的末尾添加由src指定的另一个数组的内容。函数返回加入的第一个元素的序号。2. 访
26、问简单数组集合类的元素在MFC中,一个简单数组集合类元素的访问既可以使用GetAt函数,也可使用“”操作符,例如:/CObArray:operator 示例CObArray array;CAge*pa; /CAge是一个用户类array.Add(new CAge(21); /添加一个元素array.Add(new CAge(40); /再添加一个元素pa=(CAge*)array0; /获取元素0array0=new CAge(30); /替换元素0/CObArray:GetAt示例CObArray array;array.Add(new CAge(21); /元素0array.Add(new
27、 CAge(40); /元素13. 删除简单数组集合类的元素删除简单数组集合类中的元素一般需要进行以下几个步骤:(1)使用函数GetSize和整数下标值访问简单数组集合类中的元素。(2)若对象元素是堆内存中创建的,则使用delete操作符删除每个对象元素。(3)调用函数RemoveAll删除简单数组集合类中的所有元素。例如,下面代码是一个CObArray的删除示例:CObArray array;CAge* pa1; CAge* pa2; array.Add(pa1=new CAge(21); array.Add(pa2=new CAge(40); ASSERT(array.GetSize()=
28、2);for(int i=0;iarray.GetSize();i+)delete array.GetAt(i);array.RemoveAll(); 需要说明的是:函数RemoveAll表示删除数组中的所有元素,而函数RemoveAll(int nIndex,int nCount=1)则表示要删除数组中从序号为nIndex元素开始的,数目为nCount的元素。下面来看一个示例,用来读取打开的文档内容并显示在文档窗口(视图)中。(1)用MFC AppWizard(exe)创建一个默认的单文档应用程序Ex_Array。(2)为CEx_ArrayDoc类添加一个类型为CStringArray的成员
29、变量m_strContents,用来读取文档内容。(3)在CEx_ArrayDoc:Serialize函数中添加读取文档内容的代码:void CEx_ArrayDoc:Serialize(CArchive& ar)if(ar.IsStoring()elseCString str;m_strContents.RemoveAll();while(ar.ReadString(str) m_strContents.Add(str);(4)在CEx_ArrayView:OnDraw中添加下列代码:void CEx_ArrayView:OnDraw(CDC* pDC)CEx_ArrayDoc* pDoc=
30、GetDocument();ASSERT_VALID(pDoc);int y=0;CString str;for (int i=0;im_strContents.GetSize();i+)str=pDoc-m_strContents.GetAt(i);pDC-TextOut(0,y,str); /在视窗坐标为(0,y)处中输出文本串stry+=16;代码中,宏ASSERT_VALID用来调用AssertValid函数,而AssertValid的目的是启用“断言”机制来检验对象的正确性和合法性。通过GetDocument函数可以在视图类中访问文档类的成员,TextOut是CDC类的一个成员函数,
31、用于在视图指定位置处绘制文本内容。(5)编译运行并测试。当应用程序运行时,点击菜单“文件|打开”,可以打开任意一个文本文件,结果如下图所示。需要说明的是,该示例的功能还需要进行添加,例如显示的字体改变、行距的控制等,最主要的是不能在视图中通过滚动条来查看文档的全部内容,以后还会详细讨论这些功能的实现方法。5.3.5使用CFile类在MFC中,CFile类是一个文件I/O的基类。它直接支持非缓冲、二进制的磁盘文件的输入输出,也可以使用其派生类处理文本文件(CStdioFile)和内存文件(CMemFile)。CFile类的读写功能类似于C语言中的fread和fwrite,而CStdioFile类
32、的读写功能类似于C语言中的fgets和fputs。使用CFile类可以打开或关闭一个磁盘文件、读或写一个文件中的数据等。下面分别说明。1. 文件的打开和关闭在MFC中,使用CFile打开一个通常使用两个步骤:(1)构造一个不带指定任何参数的CFile对象。(2)调用成员函数Open并指定文件路径以及文件标志。CFile类的Open函数原型如下:BOOL Open(LPCTSTR lpszFileName,UINT nOpenFlags,CfileException* pError=NULL);其中,lpszFileName用来指定一个要打开的文件路径,该路径可以是相对的、绝对的或是一个网络文件
33、名(UNC)。nOpenFlags用来指定文件打开的标志,它的值见表5.7。pError用来处理表示操作失败产生的CfileException指针,CfileException是一个与文件操作有关的异常处理类。函数Open操作成功时返回TURE,否则为FALSE。表5.7 CFile类的文件访问方式方式含义CFile:modeCreate表示创建一个新文件,若该文件已存在,则将文件原有内容清除CFile:modeNoTruncate与CFile:modeCreate组合。若文件已存在,不会将文件原有内容清除CFile:modeRead打开文件只读CFile:modeReadWrite打开文件读
34、与写CFile:modeWrite打开文件只写CFile:modeNoInherit防止子线程继承该文件CFile:shareDenyNone共享文件的读和写,若其他线程用相关方式打开过此文件,则创建失败CFile:shareDenyRead禁止其他线程读此共享文件,若其他线程用相关方式打开过此文件,则创建失败CFile:shareDenyWrite禁止其他线程写此共享文件,若其他线程用相关方式打开过此文件,则创建失败CFile:shareExclusive禁止其他线程读写此共享文件,若其他线程用相关方式打开过此文件,即使是当前线程也会使创建失败例如,下面的代码将显示如何用读写方式创建一个新文
35、件:char* pszFileName=c:testmyfile.dat;CFile myFile;CFileException fileException;if(!myFile.Open(pszFileName,CFile:modeCreate|CFile:modeReadWrite),& fileException) TRACE(Cant open file %s,error=%un,pszFileName,fileException,m_cause);其中,若文件创建打开有任何问题,Open函数将在它的最后一个参数中返回CfileException(文件异常类)对象,TRACE宏将显示出
36、文件名和表示失败原因的代码。使用AfxThrowFileException函数将获得更详细的有关错误的报告。与文件“打开”相反的操作时“关闭”,可以使用Close函数来关闭一个文件对象,若该对象是在堆内存中创建的,还需调用delete来删除它(不是删除物理文件)。2. 文件的读写和定位CFile类支持文件的读、写、和定位操作。它们相关函数的原型如下:UNIT Read(void* lpBuf,UNIT nCount);此函数将文件中指定大小的数据读入指定的缓冲区,并返回向缓冲区传输字节数。需要说明的是,这个返回值可能小于nCount,这是因为可能到达了文件的结尾。void Write(cons
37、t void* lpBuf,UNIT nCount);此函数将缓冲区的数据写到文件中。参数lpBuf用来指定要写到文件的数据缓冲区的指针,nCount表示从数据缓冲区传送的字节数。对于文本文件,每行的换行符也被计算在内。LONG Seek(LONG lOff,UNIT nFrom);此函数用来定位文件指针的位置,若要定位的位置是合法的,此函数将返回从文件开始的偏移量。否则,返回值是不定的且激活一个CfileException对象。参数lOff用来指定文件指针移动的字节数,nFrom表示指针移动方式,它可以是CFile:begin(从文件的开始位置)、CFile:current(从文件的当前位置
38、)或CFile:end(从文件的最后位置,但lOff必须为负值才能在文件中定位,否则将超出文件)等。需要说明的是,文件刚打开时,默认的文件指针位置为0,即文件的开始位置。另外,函数void SeekToBegin()和DWORD SeekToEnd()分别将指针移动到文件开始和结尾位置,后者还将返回文件的大小。3. 获取文件的有关信息CFile还支持获取文件状态,包括文件是否存在、创建与修改的日期和时间、逻辑大小和路径等。BOOL GetStatus(CFileStatus& rStatus) const;static BOOL PASAL GetStatus(LPCTSTR, CFileSt
39、atus& rStatus);若指定文件的状态信息成功获得,该函数返回TRUE,否则返回FALSE。其中,参数lpszFileName用来指定一个文件路径,这个路径可以是相对的或是绝对的,但不能是网络文件名。rStatus用来存放文件状态信息,它是一个CFileStatus结构类型,该结构具有下列成员:CTime m_ctime/文件创建日期和时间CTime m_mtime/文件最后一次修改日期和时间CTime m_atime/文件最后一次访问日期和时间LONG m_size/文件的逻辑大小字节数,就像DOS命令中DIR所显示的大小BYTE m_attribute/文件属性char m_szF
40、ullName_MAX_PATH/文件名需要说明的是,static形式的GetStatus函数将获得指定文件名的文件状态,并将文件名复制至m_szFullName中。该函数仅获取文件状态,并没有真正打开文件,这对于测试一个文件的存在性是非常有用的。例如下面的代码:CFile theFile;char* szFileName=c:testmyfile.dat;BOOL bOpenOK;CFileStatus status;if(CFile:GetStatus(szFileName,status)/该文件已存在,直接打开bOpenOK=theFile.Open(szFileName,CFile:m
41、odeWrite);else/该文件不存在,需要使用modeWrite方式创建它bOpenOK=theFile.Open(szFileName,CFile:modeCreate|CFile:modeWrite);4. CFile示例下面来看一个示例,如下图所示,单击“打开”按钮,将弹出文件“打开”对话框,从中选择一个文件时,编辑框上方显示出该文件的路径名、创建时间和文件大小,并在编辑框中显示该文件的内容。(1)创建一个默认对话框应用程序Ex_File。(2)将对话框的标题设为“使用CFile”。删除静态文本控件“TODO:在这里设置对话控制”和“取消”按钮,并将“确定”按钮的标题改为“退出”。
42、(3)打开对话框网格,参照上图添加控件并布局。 添加一个静态文本框,其ID号改为IDC_STATIC_TITLE,删除其标题“Static”,其属性分别选择“可视”(Visible)、“垂直居中”(Center vertically)和“凹陷”(Sunken),其作用是用来显示打开文件的相关信息。 添加一个编辑框,其ID号保留IDC_EDIT1,其属性选择“可视”(Visible)、“多行”(Multiline)、“水平滚动”(Horizontal scroll)、“垂直滚动”(Vertical scroll)、“自动垂直滚动”(Auto VScroll)和“带边框”(Border),其作用是
43、用来显示打开的文件内容。 添加一个按钮,其ID号改为IDC_BUTTON_OPEN,其标题改为“打开”。(4)按Ctrl+W,打开ClassWizard,切换到Member Variables选项卡,在Class name栏选CEx_FileDlg,为IDC_STATIC_TITLE控件添加类型为Value的成员变量m_strTile,为IDC_EDIT1控件添加类型为Value的成员变量m_strContent。(5)再次打开ClassWizard,切换到Message Maps选项卡,为CEx_FileDlg类添加按钮IDC_BUTTON_OPEN的BN_CLICKED消息的映射,保留默认
44、的映射函数名,并添加下列代码:void CEx_FileDlg:OnButtonOpen()CString filter;filter=文本文件(*.txt)|*.txt|C+文件(*.h,*.cpp)|*.h;*.cpp|;CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY,filter);if(dlg.DoModal()!=IDOK) return;CString strFileName=dlg.GetPathName();CFileStatus status;if(!CFile:GetStatus(strFileName,status)MessageBox(该文件不存在!);return;m_strTitle.Format(%s%s,%ld字节,strFileName,status.m_ctime.Format(%Y-%m-%d),status.m_size);UpdateData(FALSE);/打开文件,并读取数据m_strContent.Empty();CFile theFile;if(!theFile.Open(strFileName,CFile:modeRead)MessageBox(该文件无法打开!);return;char szBuffer80