首页 > 代码库 > 单文档程序结构
单文档程序结构
创建过程
下面展示建一个单文档程序的过程,在MFC Application Wizard中第一步做如下选择
不妨Project style选择MFC stardard,Visual style and colors选择Windows Native/Default,其他的选项将创建不同样式的界面。
下一步Compound document support按默认选择None;
下一步是Document Template String文档模板字符串的设置,用于设置文档视结构的一些属性,如下
各选项的意义如下
File Extension
指定应用程序创建的文档所用的文件名后缀。输入后缀名txt(不需要·号),表明Editor使用文本文件的后缀名TXT。
File ID
用于在Windows95的注册数据库中标识应用程序的文档类型。
Main Frame Caption
主框架窗口使用得标题,缺省情况下与项目名相一致,你当然可以将它改为任何你喜欢的名字,如Editor for Windows等。
Doc Type name
文档类型名,指定与一个从CDocument派生的文档类相关的文档类型名。
Filter Name
用作“打开文件”、“保存文件”对话框中的过滤器。当你在File Extension中输入后缀名是,Visual Studio会自动给你生成一个过滤器:Editor Files(*.txt)。这样,当你在Open File对话框中选择Editor Files(*.txt)时,只有以txt为后缀名的文件名显示在文件名列表中。
File new name(short name)
用于指定在new对话框中使用的文档名。当应用程序支持多种文档类型时,选择File-New菜单项会弹出一个对话框,列出应用程序所支持的所有文档类型,供用户选择。选择一种文档类型后,自动创建相应类型的文档。
File Type name(long name)
用于指定当应用程序作为OLE Automation服务器时使用的文档类型名。使用缺省值。
后面的选择中有用于设置主框架窗口的一些属性,包括框架窗口是否使用最大化按钮、最小化按钮,窗口启动时是否最大化或最小化等。根据自己的要求做相应的设定即可。
最后一步,展示了将要创建的类的名字,其中视类可以修改基类,如下
最后Finish结束。
文档/视结构中的主要类
在名为Editor的框架程序中,与文档视结构相关的类有CEditorApp、CMainFrame、CEditorView和CEditorDoc,它们分别是应用程序类CWinApp、框架窗口类CFrameWnd、视图类CView和文档类CDocument的派生类。
应用程序对象
应用程序类负责一个且唯一的一个应用程序对象的创建、初始化、运行和退出清理过程。如果在AppWizard生成框架时指定使用单文档或多文档,AppWizard会自动将File菜单下的New、Open和Printer Setup(打印机设置)自动映射到CWinApp的OnFileNew、OnFileOpen、OnFilePrintSetup成员函数,让CWinApp来处理以上这些消息。如清单7.1,浏览CEditorApp类的定义文件有关消息映射的代码。
清单7.1 CEditorApp的消息映射
BEGIN_MESSAGE_MAP(CEditorApp, CWinApp)
//{{AFX_MSG_MAP(CEditorApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
这表明,框架已经给我们生成了有关新建文档、打开文档以及打印设置的标准代码,我们不必再去做这些重复的工作了。那么,当我们新建或打开一个文档时,应用程序怎么知道要创建什么样的文档以及创建什么样的视图、框架窗口来显示该文档的呢?在文档/视结构中,应用程序通过为应用程序所支持的每一种文档创建一个文档模板,来创建和管理所有的文档类型并为它们生成相应的视图和框架窗口。
文档模板
文档模板负责创建文档、视图和框架窗口。一个应用程序对象可以管理一个或多个文档模板,每个文档模板用于创建和管理一个或多个同种类型的文档(这取决于应用程序是单文档SDI程序还是多文档MDI程序)。那些支持多种文档类型(如电子表格和文本)的应用程序,有多种文档模板对象。应用程序中的每一种文档,都必需有一种文档模板和它相对应。比如,如果应用程序既支持绘图又支持文本编辑,就需要一种绘图文档模板和文本编辑模板。
MFC提供了一个文档模板类CDocTemplate支持文档模板。文档模板类是一个抽象的基类,它定义了文档模板的基本处理函数接口。由于它是一个抽象基类,因此不能直接用它来定义对象而必需用它的派生类。对一个单文档界面程序,使用CSingleDocTemplate(单文档模板类),而对于一个多文档界面程序,使用CMultipleDocTemplate。
文档模板定义了文档、视图和框架窗口这三个类的关系。通过文档模板,我们可以知道在创建或打开一个文档时,需要用什么样的视图、框架窗口来显示它。这是因为文档模板保存了文档和对应的视图和框架窗口的CRuntimeClass对象的指针。此外,文档模板还保存了所支持的全部文档类的信息,包括这些文档的文件扩展名信息、文档在框架窗口中的名字、代表文档的图标等信息。
提示:每个从CObject派生的类都与一个CRuntimeClass结构相关联。通过这个结构,你可以在程序运行时刻获得关于一个对象和它的基类的信息。在函数参数需要作附加类型检查时,这种运行时刻判别对象类型的能力是非常重要的。C++本身并不支持运行时刻类信息。CRuntimeClass结构包含一个以\0结尾的字符串类名、整型的该类对象大小、基类的运行时刻信息等。
一般在应用程序的InitInstance成员函数实现中创建一个或多个文档模板,如清单7.2。
清单7.2 CEditorApp的InitInstance成员函数定义
BOOL CEditorApp::InitInstance()
{
//标准的初始化代码
//......
// Register the application‘s document templates. Document templates
// serve as the connection between documents, frame windows and views.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CEditorDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CEditorView));
AddDocTemplate(pDocTemplate);
//其他的初始化代码和主框架窗口显示过程
//......
// Enable DDE Execute open
EnableShellOpen();
RegisterShellFileTypes(TRUE);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update it.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
// Enable drag/drop open
m_pMainWnd->DragAcceptFiles();
}
在InitInstance中,首先声明一个CSingleDocTemplate*类型的单文档模板对象指针(因为这里的文本编辑器使用单文档界面)。然后创建该类型的模板对象。如果要使用多文档界面,只需要将这里的CSingleDocTemplate改为CMultiDocTemplate,当然CMainFrame也要改为从CFrameWnd改为CMDIChildWnd或其派生类。
在CSingleDocTemplate构造函数中,还包含一个IDR_MAINFRAME参数。它指向一个字符串资源,这个字符串给出了文档所使用及显示时所要求的几个选项,包括文档名字、文档的文件扩展名、在框架窗口上显示的名字等等,我们称之为文档模板字符串。有关文档模板字符串还将在下一章使用多个文档模板这一节作详细阐述,因此这里就不展开讲了。
然后InitInstance调用AddDocTemplate将创建好的文档模板加入到应用程序可用的文档模板链表中去。这样,如果用户选择了File-New或File-Open菜单要求创建或打开一个文档时,应用程序类的OnNewDocument成员函数和OnOpenDocument()成员函数就可以从文档模板链表中检索出文档模板提示用户选择适当的文档类型并创建文档及相关的视图、框架窗口。
文档
Editor的文档类CEditorDoc从CDocument派生下来,它规定了应用程序所用的数据。如果需要在应用程序中提供OLE功能,则需要从COleDocument或其派生类派生出自己的文档类。
视图
Editor的视图类从CView派生,它是数据的用户窗口。视图规定了用户查看文档数据以及同数据交互的方式。有时一个文档可能需要多个视图。
如果文档需要卷滚,需要从CScrollView派生出视图类。如果希望视图按一个对话框模板资源来布置用户界面,可以从CFormView派生。由于CFormView经常同数据库打交道,因此我们把它放在第十章“数据库技术”中结合数据库技术讲解。感兴趣的读者可以先看看Visual C++ MFC例子CHKBOOK(在SAMPLES\MFC\GENERAL\CHKBOOK目录下)。
框架窗口
视图在文档框架窗口中显示,它是框架窗口的子窗口。框架窗口作用有二:一是为视图提供可视的边框,还包括标题条、一些标准的窗口组件(最大、最小化按钮、关闭按钮),象一个容器一样把视图装起来。二是响应标准的窗口消息,包括最大化、最小化、调整尺寸等。当框架窗口关闭时,在其中的视图也被自动删除。视图和框架窗口关系下图所示:
对于SDI程序,文档框架窗口也就是应用程序的主框架窗口。在MDI应用程序中,文档框架窗口是显示在主框架窗口中的子窗口(通常是CMDIChildWnd或其派生类)。
可以从主框架窗口类派生出新类来包含你的视图,并指定框架的风格和其他特征。如果是SDI程序,则从CFrameWnd派生出文档框架窗口:
class CMainFrame:public CFrameWnd
{
...
};
如果是MDI窗口,则需要从CMDIFrameWnd派生出主框架窗口,同时再从CMDIChildWnd或其派生类派生出一个新类,来定制特定文档窗口的属性和功能。
在应用程序运行过程中,以上几种类型的对象相互协作,来处理命令和消息。一个且唯一的一个应用程序对象管理一个或多个文档模板,每个文档模板创建和管理一个(SDI)或多个文档(MDI)。用户通过包含在框架窗口中的视图来浏览和操作文档中的数据。在SDI应用程序中,以上对象关系如下图所示。
单文档程序结构