⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chap7_2.htm

📁 非常好的应用vc++6.0进行相关网络程序开发的教程
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<title>7.2文档视结构程序实例</title>
</head>

<body link="#3973DE" alink="#3973DE">
<font SIZE="5"><div align="center"><center>

<table border="0" width="615" cellspacing="0" cellpadding="0">
  <tr>
    <td><div align="center"><center><table border="0" width="615" cellpadding="0" cellspacing="0" height="20">
      <tr>
        <td width="377" bgcolor="#15397D" height="20"></td>
        <td width="238" bgcolor="#000000" height="20"><p align="right"></font><span style="text-decoration: none"><a href="../../index.htm"><font color="#FFFFFF">电脑报Visual 
        C++网络教程</font></a></span></td>
      </tr>
    </table>
    </center></div><p ALIGN="CENTER"><font color="#3973DE"><big><big>7.2文档视结构程序实例</big></big></font><font size="5"></p>
    <p></font><font SIZE="3">下面,我们以一个简单的文本编辑器为例,说明文档/视结构的原理及应用。由于我们重在讨论文档/视结构而不是编辑器的实现,因此这个编辑器设计的非常简单:用户只能逐行输入字符,以回车结束一行并换行,不支持字符的删除和插入,也没有光标指示当前编辑位置。另外,用户可以选择编辑器显示文本时所使用的字体。</p>
    <p align="center"></font><img src="T7_4.gif" alt="T7_4.tif (297712 bytes)" WIDTH="508" HEIGHT="388"><font SIZE="3"></p>
    <p align="center">图7-4</p>
    <p ALIGN="JUSTIFY">首先,使用AppWizard生成编辑器程序的框架:在New对话框的Project 
    Name编辑框中输入项目名为Editor。在AppWizard的第一步选择Single document 
    ,这将创建一个SDI应用程序。AppWizard第二和第三步选项使用缺省值。在AppWizard 
    Step 4 of 6对话框中,如图7-4所示,细心的读者或许会注意到在这一页里,有一个Advanced按钮,以前没有提到过。现在揿击该按钮,弹出Advanced 
    Option对话框,如图7-5所示。Advanced Option对话框是用来设置文档视结构和主框架窗口的一些属性的。</p>
    <p align="center"></font><img src="T7_5.gif" alt="T7_5.tif (216970 bytes)" WIDTH="439" HEIGHT="466"><font SIZE="3"></p>
    <p align="center">图7-5</p>
    <p>该对话框提供两个标签页,一页是Document Template String(文档模板字符串,有关文档模板字符串,我们还将在后面作详细介绍),用于设置文档视结构的一些属性。它包括以下几个编辑框:</p>
    <p>File Extension:指定应用程序创建的文档所用的文件名后缀。输入后缀名txt(不需要&middot;号。),表明Editor使用文本文件的后缀名TXT。</p>
    <p>File ID:用于在Windows95的注册数据库中标识应用程序的文档类型。</p>
    <p>MainFrame Caption:主框架窗口使用得标题,缺省情况下与项目名相一致,你当然可以将它改为任何你喜欢的名字,如Editor 
    for Windows等。</p>
    <p>Doc Type name:文档类型名,指定与一个从CDocument派生的文档类相关的文档类型名。</p>
    <p>Filter Name:用作“打开文件”、“保存文件”对话框中的过滤器。当你在File 
    Extension中输入后缀名是,Visual Studio会自动给你生成一个过滤器:Editor 
    Files(*.txt)。这样,当你在Open File对话框中选择Editor Files(*.txt)时,只有以txt为后缀名的文件名显示在文件名列表中。</p>
    <p>File new name(short name):用于指定在new对话框中使用的文档名。当应用程序支持多种文档类型时,选择File-New菜单项会弹出一个对话框,列出应用程序所支持的所有文档类型,供用户选择。选择一种文档类型后,自动创建相应类型的文档。这里我们只支持编辑器这一种文档类型,故使用缺省值。</p>
    <p>File Type name(long name):用于指定当应用程序作为OLE Automation服务器时使用的文档类型名。使用缺省值。 
    </p>
    <p>另一页是Window Styles,用于设置主框架窗口的一些属性,包括框架窗口是否使用最大化按钮、最小化按钮,窗口启动时是否最大化或最小化等。这里我们使用缺省值,不需要作任何修改。</p>
    <p>按OK按钮,关闭Advanced Option对话框。</p>
    <p>AppWizard后面的几页对话框都使用缺省值。创建完Editor框架程序后,Visual 
    Studio自动打开Editor工程。现在要修改Editor框架程序,往程序中添加代码,实现编辑器功能。</p>
    <p></font><font color="#3973DE" SIZE="3">7.2.1 </font><font SIZE="3"><font color="#3973DE">文档/视结构中的主要类</font></p>
    <p> </p>
    <p>在Editor框架程序中,与文档视结构相关的类有CEditorApp、CMainFrame、CEditorView和CEditorDoc,它们分别是应用程序类CWinApp、框架窗口类CFrameWnd、视图类CView和文档类CDocument的派生类。</p>
    <p><font color="#3973DE">应用程序对象</font></p>
    <p>其中,应用程序类负责一个且唯一的一个应用程序对象的创建、初始化、运行和退出清理过程。如果在AppWizard生成框架时指定使用单文档或多文档,AppWizard会自动将File菜单下的New、Open和Printer 
    Setup(打印机设置)自动映射到CWinApp的OnFileNew、OnFileOpen、OnFilePrintSetup成员函数,让CWinApp来处理以上这些消息。如清单7.1,浏览CEditorApp类的定义文件有关消息映射的代码。</p>
    <p>清单7.1 CEditorApp的消息映射</p>
    <p>BEGIN_MESSAGE_MAP(CEditorApp, CWinApp)</p>
    <p>//{{AFX_MSG_MAP(CEditorApp)</p>
    <p>ON_COMMAND(ID_APP_ABOUT, OnAppAbout)</p>
    <p>// NOTE - the ClassWizard will add and remove mapping macros here.</p>
    <p>// DO NOT EDIT what you see in these blocks of generated code!</p>
    <p>//}}AFX_MSG_MAP</p>
    <p>// Standard file based document commands</p>
    <p> </p>
    <p>ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)</p>
    <p>ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)</p>
    <p>// Standard print setup command</p>
    <p> </p>
    <p>ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)</p>
    <p>END_MESSAGE_MAP()</p>
    <p>这表明,框架已经给我们生成了有关新建文档、打开文档以及打印设置的标准代码,我们不必再去做这些重复的工作了。那么,当我们新建或打开一个文档时,应用程序怎么知道要创建什么样的文档以及创建什么样的视图、框架窗口来显示该文档的呢?在文档/视结构中,应用程序通过为应用程序所支持的每一种文档创建一个文档模板,来创建和管理所有的文档类型并为它们生成相应的视图和框架窗口。</p>
    <p><font color="#3973DE">文档模板</font></p>
    <p>文档模板负责创建文档、视图和框架窗口。一个应用程序对象可以管理一个或多个文档模板,每个文档模板用于创建和管理一个或多个同种类型的文档(这取决于应用程序是单文档SDI程序还是多文档MDI程序)。那些支持多种文档类型(如电子表格和文本)的应用程序,有多种文档模板对象。应用程序中的每一种文档,都必需有一种文档模板和它相对应。比如,如果应用程序既支持绘图又支持文本编辑,就需要一种一种绘图文档模板和文本编辑模板。在下一章里,我们举了一个这样的例子,来说明多种文档模板的实现技术。</p>
    <p>MFC提供了一个文档模板类CDocTemplate支持文档模板。文档模板类是一个抽象的基类,它定义了文档模板的基本处理函数接口。由于它是一个抽象基类,因此不能直接用它来定义对象而必需用它的派生类。对一个单文档界面程序,使用CSingleDocTemplate(单文档模板类),而对于一个多文档界面程序,使用CMultipleDocTemplate。</p>
    <p>文档模板定义了文档、视图和框架窗口这三个类的关系。通过文档模板,我们可以知道在创建或打开一个文档时,需要用什么样的视图、框架窗口来显示它。这是因为文档模板保存了文档和对应的视图和框架窗口的CRuntimeClass对象的指针。此外,文档模板还保存了所支持的全部文档类的信息,包括这些文档的文件扩展名信息、文档在框架窗口中的名字、代表文档的图标等信息。</p>
    <div align="center"><center><table border="2" cellpadding="2" cellspacing="0" width="100%" bgcolor="#ACE4FF">
      <tr>
        <td width="100%">提示:每个从CObject派生的类都与一个CRuntimeClass结构相关联。通过这个结构,你可以在程序运行时刻获得关于一个对象和它的基类的信息。在函数参数需要作附加类型检查时,这种运行时刻判别对象类型的能力是非常重要的。C++本身并不支持运行时刻类信息。CRuntimeClass结构包含一个以\0结尾的字符串类名、整型的该类对象大小、基类的运行时刻信息等。</font></td>
      </tr>
    </table>
    </center></div><p><font SIZE="3"> </p>
    <p>一般在应用程序的InitInstance成员函数实现中创建一个或多个文档模板,如清单7.2。</p>
    <p>清单7.2 CEditorApp的InitInstance成员函数定义</p>
    <p>BOOL CEditorApp::InitInstance()</p>
    <p>{</p>
    <p>//标准的初始化代码</p>
    <p>//......</p>
    <p>// Register the application's document templates. Document templates</p>
    <p>// serve as the connection between documents, frame windows and views.</p>
    <p>CSingleDocTemplate* pDocTemplate;</p>
    <p>pDocTemplate = new CSingleDocTemplate(</p>
    <p>IDR_MAINFRAME,</p>
    <p>RUNTIME_CLASS(CEditorDoc),</p>
    <p>RUNTIME_CLASS(CMainFrame), // main SDI frame window</p>
    <p>RUNTIME_CLASS(CEditorView));</p>
    <p>AddDocTemplate(pDocTemplate);</p>
    <p>//其他的初始化代码和主框架窗口显示过程</p>
    <p>//......</p>
    <p>// Enable DDE Execute open</p>
    <p>EnableShellOpen();</p>
    <p>RegisterShellFileTypes(TRUE);</p>
    <p>// Parse command line for standard shell commands, DDE, file open</p>
    <p>CCommandLineInfo cmdInfo;</p>
    <p>ParseCommandLine(cmdInfo);</p>
    <p>// Dispatch commands specified on the command line</p>
    <p>if (!ProcessShellCommand(cmdInfo))</p>
    <p>return FALSE;</p>
    <p>// The one and only window has been initialized, so show and update it.</p>
    <p>m_pMainWnd-&gt;ShowWindow(SW_SHOW);</p>
    <p>m_pMainWnd-&gt;UpdateWindow();</p>
    <p>// Enable drag/drop open</p>
    <p>m_pMainWnd-&gt;DragAcceptFiles();</p>
    <p>}</p>
    <p> </p>
    <p>在InitInstance中,首先声明一个CSingleDocTemplate*类型的单文档模板对象指针(因为这里的文本编辑器使用单文档界面)。然后创建该类型的模板对象。如果要使用多文档界面,只需要将这里的CSingleDocTemplate改为CMultiDocTemplate,当然CMainFrame也要改为从CFrameWnd改为CMDIChildWnd或其派生类。</p>
    <p>在CSingleDocTemplate构造函数中,还包含一个IDR_MAINFRAME参数。它指向一个字符串资源,这个字符串给出了文档所使用及显示时所要求的几个选项,包括文档名字、文档的文件扩展名、在框架窗口上显示的名字等等,我们称之为文档模板字符串。有关文档模板字符串还将在下一章使用多个文档模板这一节作详细阐述,因此这里就不展开讲了。</p>
    <p>然后InitInstance调用AddDocTemplate将创建好的文档模板加入到应用程序可用的文档模板链表中去。这样,如果用户选择了File-New或File-Open菜单要求创建或打开一个文档时,应用程序类的OnNewDocument成员函数和OnOpenDocument()成员函数就可以从文档模板链表中检索出文档模板提示用户选择适当的文档类型并创建文档及相关的视图、框架窗口。</p>
    <p><font color="#3973DE">文档</font></p>
    <p>Editor的文档类CEditorDoc从CDocument派生下来,它规定了应用程序所用的数据。如果需要在应用程序中提供OLE功能,则需要从COleDocument或其派生类派生出自己的文档类。</p>
    <p><font color="#3973DE">视图</font></p>
    <p>Editor的视图类从CView派生,它是数据的用户窗口。视图规定了用户查看文档数据以及同数据交互的方式。有时一个文档可能需要多个视图。</p>
    <p ALIGN="JUSTIFY">如果文档需要卷滚,需要从CScrollView派生出视图类。如果希望视图按一个对话框模板资源来布置用户界面,可以从CFormView派生。由于CFormView经常同数据库打交道,因此我们把它放在第十章“数据库技术”中结合数据库技术讲解。感兴趣的读者可以先看看Visual 
    C++ MFC例子CHKBOOK(在SAMPLES\MFC\GENERAL\CHKBOOK目录下)。</p>
    <p><font color="#3973DE">框架窗口</font></p>
    <p>视图在文档框架窗口中显示,它是框架窗口的子窗口。框架窗口作用有二:一是为视图提供可视的边框,还包括标题条、一些标准的窗口组件(最大、最小化按钮、关闭按钮),象一个容器一样把视图装起来。二是响应标准的窗口消息,包括最大化、最小化、调整尺寸等。当框架窗口关闭时,在其中的视图也被自动删除。视图和框架窗口关系如图7-6所示:</p>
    <p align="center"></font><img src="T7_6.gif" alt="T7_6.tif (129540 bytes)" WIDTH="440" HEIGHT="273"><font SIZE="3"></p>
    <p align="center">图7-6 视图和框架窗口的关系</p>
    <p>对于SDI程序,文档框架窗口也就是应用程序的主框架窗口。在MDI应用程序中,文档框架窗口是显示在主框架窗口中的子窗口(通常是CMDIChildWnd或其派生类)。</p>
    <p>可以从主框架窗口类派生出新类来包含你的视图,并指定框架的风格和其他特征。如果是SDI程序,则从CFrameWnd派生出文档框架窗口:</p>
    <p>class CMainFrame:public CFrameWnd</p>
    <p>{</p>
    <p>...</p>
    <p>};</p>
    <p>如果是MDI窗口,则需要从CMDIFrameWnd派生出主框架窗口,同时在从CMDIChildWnd或其派生类派生出一个新类,来定制特定文档窗口的属性和功能。</p>
    <p>在应用程序运行过程中,以上几种类型的对象相互协作,来处理命令和消息。一个且唯一的一个应用程序对象管理一个或多个文档模板,每个文档模板创建和管理一个(SDI)或多个文档(MDI)。用户通过包含在框架窗口中的视图来浏览和操作文档中的数据。在SDI应用程序中,以上对象关系如图7-7所示。</p>
    <p align="center"></font><img src="T7_7.gif" alt="T7_7.tif (117560 bytes)" WIDTH="344" HEIGHT="237"></p>
    <p align="center"><font SIZE="3">图7-7 在SDI程序中各对象的关系</font></p>
    <p><font color="#3973DE">7.2.2 设计文本编辑器的文档类</font><font SIZE="3"></p>
    <p>弄清这些对象的关系以后,就可以着手往框架里填写代码,实现我们的文本编辑器程序了。从以上分析可以看出,文档视结构程序的主要工作在于文档和视图的设计。</p>
    <p>首先设计文档。程序=数据+算法,在MFC文档/视结构中,最关键的就是文档的设计。怎样保存用户输入的文本行?方法之一是保存一组指针,每个指针指向一个文本行。如果使用C语言来写这个程序的话,需要分配内存来存放这些指针,还要自己编写文本行的动态分配、增加、删除等例程。但是MFC简化这些工作,它提供了集合类(collection 
    classes)。</p>
    <p>集合类是用来容纳和处理一组对象或标准数据类型变量的C++类。每个集合类对象可以看作一个单独的对象。类成员函数可作用于集合的所有元素。MFC提供两种类型的集合类:</p>
    <blockquote>
      <p>基于模板的集合类</p>
      <p>非基于模板的集合类</p>
    </blockquote>
    <p>这两种集合类 
    对用户来说非常相似。基于模板的集合所包含的元素是用户自定义的数据结构或者说是抽象的数据结构,它以数组、链表和映射表三种方式组织用户自定义的数据结构。使用基于模板的集合类需要用户作一些类型转换工作。非基于 
    模板的集合类提供的是一组现成的、用于某种预定义的数据类型(如CObject、WORD、BYTE、DWORD、字符串等)的集合。在设计程序时,如果所用的数据类型是预定义的,如下面的编辑要用到的字符串,则使用非基于模板的集合类;如果所用得数据类型是用户自定义的数据结构类型,那就要用到基于模板的集合类。</p>
    <p>根据对象在集合中的组织合存储方式,集合类又可分为三种类型:链表、数组、映射(或字典)。应当根据特定的编程问题,选择适当的类型。</p>
    <p>链表:链表类用双向链表实现有序的、非索引的元素链表。链表有一个头或尾。很容易从头或尾增加或删除元素、遍历所有元素,在中间插入或删除元素。链表在需要增加、删除元素的场合效率很高。非基于模板的链表有三种:CObList、CPtrList、CStringList,分别用于管理对象指针、无类型指针和字符串。可以使用链表创建堆栈和队列。</p>
    <p>要访问链表的成员,可以使用GetNext和GetHeadPosition()。</p>
    <p>要删除链表的成员,可以用GetHeadPosition()和GetNext()来遍历链表,然后用delete删除其中的对象,最后调用RemoveAll删除链表所包含的指针。</p>
    <p>数组类提供一个可动态调整数组大小的、有序的、按整数索引的对象数组。数组在内存中连续的存放固定长度的数组元素。数组的最大优点是可以随时存取任一元素。数组类包括基于模板的CArray,它可以存放任何类型的数据;MFC还为字节、字、双字、CString对象、CObject指针和无类型指针提供了预定义的类。数组的元素可以通过一个以零为基础的整数下标直接进行访问。下标操作符([])可用于设置或检取数组元素。如果要设置一个超过数组当前范围的元素,可以指定该数组是否自动增大。但是如果要调整数组大小时,则数组占用的内存块需要重新移动,效率很低。如果不要求调整数组大小,则对数组集合的访问和对标准C数组的访问一样快。在使用数组之前,应使用SetSize建立其大小,并分配内存。若不用SetSize,象数组添加元素时会导致频繁的再分配内存和拷贝数据。数组类适用于那些需要快速检索、很少需要增加或删除元素的集合。</p>
    <p>数组通过GetAt(索引值)来访问数组中的成员。</p>
    <p>要删除数组中的成员,可以用GetSize()取得大小,然后遍历数组中成员,用delete删除,然后调用RemoveAll()清除其中的指针数据。</p>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -