MFC中实现多文档

MFC中实现多文档
MFC中实现多文档

MFC中实现多文档.txt-//自私,让我们只看见自己却容不下别人。如果发短信给你喜欢的人,他不回,不要再发。看着你的相片,我就特冲动的想P成黑白挂墙上!有时,不是世界太虚伪,只是,我们太天真。MFC中实现多文档(转)2007-12-27 21:21

MDI (Multiple Document Interface) 是Windows 界面的一种规范,它建立多个窗口来浏览文档数据,如Windows 中的Program Manager 等都是按MDI 规范实现的。在实际工程软件开发中,许多程序员将其作为一种实现多窗口的标准方法。微软基础类库(Microsoft Foundation Class Library, 简称MFC 库), 是微软公司为方便Windows 程序开发所提供的一个功能强大的通用类库。MFC 的核心是以类的形式封装了大量Windows API。在可视化编程语言VC++ 下应用MFC 是目前开发Windows 程序最方便的途径之一。VC++ 提供的各种开发工具如AppWizard、ClassWizard 和App Studio, 可以建立起具备基本功能的Windows 框架程序(Framework)。而程序员所需要做的工作就是将自己特有的代码填入到框架程序中去,从而极大地减少了用户界面编程的工作量,加快了开发速度。关于MDI 的标准开发方法可参考一般的Windows 编程书籍,本文将介绍利用MFC 实现MDI 界面。

MFC 2.0 以上版本支持“文档/ 浏览视窗”(Document/View) 结构模式。由文档负责管理数据,浏览视窗负责数据显示及与用户的交互,从而实现了数据与界面的分离,使整个程序设计更具规范化、模块化。MFC 中,“文档”由类CDocument 及其派生类实现( 简称Doc 类);“浏览视窗”由类CView 及其派生类实现 ( 简称View 类)。二者都包含于应用程序的框架窗口中,并由其管理。使用单文档时,框架窗口由类CFrameWnd 及其派生类实现;使用多文档时,框架窗口是利用类CMDIFrameWnd 和CMDIChildWnd 实现。由文档模板将文档、浏览窗口和框架窗口三者联系起来。

当程序员在App Wizard 的Option 选项中选择 Multiple Document Interface 时,MFC 构架程序(Framework) 将自动生成实现MDI 基本功能的代码。类CMDIFrameWnd 负责整个应用程序的主框架窗口;类CMDIChildWnd 实现MDI 的子窗口框架,它不带菜单项,而与主框架窗口共享菜单。主框架窗口依据当前激活的子窗口自动更换菜单项。CView 则负责MDI 子窗口客户区中显示的具体内容。例如,App Wizard 的以M01 为Project 名建立的构架程序(framework) 中包括一些基本类:主框架窗口CMainFrame:派生自CMDIFrameWnd;文档CM01Doc :派生自CDocument;浏览窗口CM01View:派生自CView;其中CM01Doc、CM01View 和CMDIChildWnd 由多文档模板CMultiDocTemplate 联系在一起。在CM01App::InitInstance() 函数中代码如下:

BOOL CM01App::InitInstance()

{

......

CMultiDocTemplate* pDocTemplate;

// CMultiDocTemplate 用于MDI 文档

pDocTemplate = new CMultiDocTemplate(

IDR_M01TYPE,// 资源标识

RUNTIME_CLASS(CM01Doc),

// 文档类

RUNTIME_CLASS(CMDIChildWnd),

// 标准MDI 子窗口框架

RUNTIME_CLASS(CM01View));

// 浏览视窗类

AddDocTemplate(pDocTemplate);

// 为整个应用程序添加新模板

......

}

此时,数据Doc 类仅与一种View 类相关联,MDI 每个子窗口显示的内容是一致的。如果用户希望不同的子窗口显示不同的文档,则需要分别建立新的资源项、新的文档类、新的View 类,并且用新模板将他们与CMDIChildWnd 联系起来即可。MFC 框架程序将复杂的消息发送和接收机制隐藏起来,自动实现子窗口的调度安排。程序员只需设定自己的数据,并在各个View 中重载OnDraw() 函数,完成所需的绘制。

然而在实际开发应用程序中,常常希望对某一类数据进行不同方式的显示,既可观察数值,又可有图形显示。这就要求同一种Doc 类与多个View 类相关联,而每个View 类对应一个不同的MDI 子窗口。CMultiDocTemplate 的典型用法是建立独立的文档结构和View 对象。而下面CMultiDocTemplate 将使用同一文档和多个View 类。

(1) 用ClassWizard 建立一新的View 类:CM02View。

(2) 建立新模板:

CMultiDocTemplate* pDocTemplate02=new CMultiDocTemplate(

IDR_M01TYPE, // 使用同一资源

RUNTIME_CLASS(CM01Doc), // 同一文档

RUNTIME_CLASS(CMDIChildWnd), // 标准MDI 子窗口框架

RUNTIME_CLASS(CM02View)); // 新View

然后使用CApp::AddDocTemplate 函数添加新模板。

如果此时仍然在CM01App::InitInstance() 函数中添加新模板,则构架程序会错误地认为程序支持两种文档类型,从而在编译产生的EXE 文件执行时弹出对话框,要求用户选择文档类型。而实际上两种文档类型是一样的。

为避免此种情况,可使用MFC 开发者建议的方法:在前例情况下,首先,应在App Studio 中将字串资源IDR_M01TYPE 复制为一个新字串资源IDR_M02TYPE。然后,删去字串资源IDR_M02TYPE 中第二个

后的字符串M01 Document( 该字串即为CDocTemplate::fileNewName 项)。之后,用新资源IDR_M02TYPE 来建立第二个模板。这样编译的EXE 文件将不会弹出对话框。在研究MFC 的源码之后,发现之所以弹出文档类型对话框,是由于CM01App::InitInstance() 函数中调用了OnFileNew() 函数。OnFileNew() 函数检查文档模板数量;当不止一个模板时,则弹出对话框;待用户选择之后,按所选的文档类型建立MDI 窗口。由于删去了第二个模板的fileNewName 项,无法显示文档类型,就自动停止对话框,而将第一种类型作为缺省文档类型建立MDI 窗口。

在工程应用程序中,OnFileNew() 函数一般只在程序初始化时调用一次( 至于菜单File |New 的响应,用户可接管处理),所以可以不在CMyApp::InitInstance() 函数中添加新文档模板,躲过OnFileNew() 函数的检查,而在需要的时候添加所需的文档模板,建立新的子窗口。这样既避免了文档类型对话框,又不必增加字串资源。

一种简单的例子如下:第一个子窗口仍由构架程序自动建立;设定一个新的菜单项“新窗口(NewWindow)”,在CMainFrame 中处理该菜单消息,消息响应函数中显示第二个子窗口。

void CMainFrame::OnNewWindow()

{

// 添加新的文档模板

static CMultiDocTemplate* pDocTemplate_New;

static BOOL bChildCreated=FALSE;

// 标志,新窗口是否建立; 如已建,将不重建

if(bChildCreated==FALSE)

{

pDocTemplate_New = new CMultiDocTemplate(

IDR_M01TYPE, // 使用同一资源

RUNTIME_CLASS(CM01Doc),

RUNTIME_CLASS(CMDIChildWnd),

// 标准MDI 子窗口框架

RUNTIME_CLASS(CM02View));

AfxGetApp()->AddDocTemplate(pdocTemplate_New);

// 创建新的子窗口

CMDIChildWnd* pMDIActive = MDIGetActive(); // 获得当前活动子窗口的指针

CMpvDoc* pDoc = (CMpvDoc*)pMDIActive->GetActiveDocument(); // 获得文档指针

CMDIChildWnd* pNewFrame=(CMDIChildWnd*) (pDocTemplate_New ->CreateNewFrame(pDoc, NULL));

// 建立新的框架窗口

if (pNewFrame == NULL)

{

AfxMessageBox(" 新窗口不能建立",MB_OK,0);

return; // not created

}

pDocTemplate_New ->InitialUpdateFrame(pNewFrame, pDoc); // 显示窗口

MDITile(MDITILE_HORIZONTAL); // 将多个窗口平铺

bChildCreated=TRUE;

}

不同的View 在OnDraw() 函数中有各自的绘制代码,当数据更新时,只要调用CDocument::UpdateAllViews() 函数,即可更新全部的MDI 子窗口。

以上所讨论的程序在Windows 3.1、中文之星2.0、 VC++ 1.52、MFC 2.50 环境下通过。从中可以看到:利用MFC 实现MDI,将复杂的多窗口安排交给框架程序(Framework) 来承担,编程人员可将精力集中于自己特有的任务,极大地提高了编程的效率。

相关主题
相关文档
最新文档