MFC文档/视图结构体系及SDI回顾(1)

1.文档/视图历史小传

在MFC早期,应用程序的体系结构是相当的粗浅。在早期的MFC1.0版本,应用程序具有两个主要的控件:代表应用程序自身的应用程序对象和代表应用程序窗口的窗口对象。应用程序对象的主要任务在于创建窗口,反过来窗口再处理消息。
通过引入文档视图体系结构,可以这样讲,MFC2.0基本上变革了windows应用程序编制的方式。在文档视图应用程序中,应用程序的数据由文档对象代表,而数据的视图由视图对象代表。文档和视图合作来处理用户的输入并绘制结果数据的文字以及图形表示。在新版MFC中,CDocument类是文档对象的基类;CView类是视图对象的基类。而应用程序的主窗口,其操作功能主要在MFC的CFrameWnd类和CMDIFrameWnd类中实现。
目前,MFC提供两种文档视图方案,分别是SDI(单文档结构)和MDI(多文档结构)。

2.文档/视图基础知识回顾

SDI文档/视图应用程序示意图如下:
MFC文档/视图结构体系及SDI回顾(1)_第1张图片
框架窗口是应用程序的顶层窗口;
视图是子窗口,大小与框架窗口相适应,在实际中作为框架窗口的客户区。
应用程序的数据保存在文档对象中,数据的可视化表示保存在视图中。对于SDI应用程序,框架窗口类是从CFrameWnd派生来的,文档类是从CDocument派生的,而视图类是从Cview或相关类如CScrollView派生来的。
图中的箭头我们可以理解为数据流动的方向。应用程序对象提供消息循环给框架窗口和视图提取消息。视图对象将鼠标和键盘输入转换为处理保存在文档中数据的命令,文档对象提供了视图所需要的用来输出的数据。

3.一步步剖析文档/视图结构体系

SDI文档/视图应用程序最有意思的一个方面就是框架窗口、文档和视图对象的创建方式。
再看看InitInstance函数
BOOL CSDItestApp::InitInstance()
{

	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 将它设置为包括所有要在应用程序中使用的公共控件类。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();
	// 初始化 OLE 库
	if (!AfxOleInit())
	{
		AfxMessageBox(IDP_OLE_INIT_FAILED);
		return FALSE;
	}

	AfxEnableControlContainer();
	EnableTaskbarInteraction(FALSE);
	// 使用 RichEdit 控件需要 AfxInitRichEdit2()	
	// AfxInitRichEdit2();

	// 标准初始化
	// 如果未使用这些功能并希望减小
	// 最终可执行文件的大小,则应移除下列
	// 不需要的特定初始化例程
	// 更改用于存储设置的注册表项
	// TODO: 应适当修改该字符串,
	// 例如修改为公司或组织名
	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
	LoadStdProfileSettings(4);  // 加载标准 INI 文件选项(包括 MRU)

///
	// 注册应用程序的文档模板。  文档模板
	// 将用作文档、框架窗口和视图之间的连接
	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CSDItestDoc),
		RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架窗口
		RUNTIME_CLASS(CSDItestView));
	if (!pDocTemplate)
		return FALSE;
	AddDocTemplate(pDocTemplate);


	// 分析标准 shell 命令、DDE、打开文件操作的命令行
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);
	// 调度在命令行中指定的命令。  如果
	// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;

	// 唯一的一个窗口已初始化,因此显示它并对其进行更新
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();
	return TRUE;
}
首先来看:
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CSDItestDoc),
		RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架窗口
		RUNTIME_CLASS(CSDItestView));
指:从MFC的CSingleDocTemple类创建了一个SDI文档模板。 SDI文档模板是SDI文档/视图应用程序的最主要成分。他表示了用来管理应用程序数据的文档类、包含数据视图的框架窗口类、以及用来绘制可视数据表示的视图类。
必须一提的是,文档模板保存着资源ID,主结构用它来加载菜单、加速键以及其他形成应用程序用户界面的资源。类名字括号外的RUNTIME_CLASS宏对于所指定的类返回指向CRuntimeClass就够的指针。这使得主结构可以在运行时创建这些类的对象。
if (!pDocTemplate)
		return FALSE;
AddDocTemplate(pDocTemplate);
首先判断文档编辑框是否创建成功。然后将文档模板添加到由 应用程序对象保存的文档模板列表中。SDI应用程序只注册一个文档类型,而MDI应用程序可以并且有事也注册多个类型。
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
通过CWinAPP::CCommanLine并用反映命令行输入参数的值来初始化CCommandLineInfo 对象cmdInfo;
其中通常包括文档文件名。
if (!ProcessShellCommand(cmdInfo))
	return FALSE;
“处理”命令行参数。首先,ProcessShellCommand调用CWinAPP::OnFileNew来启动应用程序,如果文件名没有在命令行上输入就是用空白文档,或者在指定了文档名称的情况下就是用CWinAPP::OpenDocumentFile来加载一个文档。正式在程序执行的这个阶段,主结构用保存在文档模板中的信息来创建文档、框架窗口和视图对象。
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
这两条语句用于在屏幕上显示应用程序的框架窗口。
在应用程序被启动,文档、框架窗口和视图被创建之后,消息循环就开始工作了,应用程序也开始检索和处理消息。我们必须记住,只有窗口才可以接收消息。

文档对象
在文档/视图体系结构中,数据被保存在文档对象中。文档对象是在主结构初始化从CDocument派生出的类时创建的。文档几乎可以指任何东西,他是程序数据的抽象表示,在数据的保存和给用户提供数据之间划分了清晰的界限。通常,文档对象为其他对象(主要是视图)提供了公用成员函数,使用它可以访问文档数据。要记得一点,所有数据的处理都有文档对象自己完成。
CDocument操作(非虚拟类成员函数)有哪些:
CDocument类的操作
GetFirstViewPosition 返回POSITION,用来传递给GetNextView,开始列举与文档关联的视图
GetNextView 返回CView指针,指向与文档关联的视图列表中下一个视图
GetPathName 检查文档的文件名称和路径
GetTitle 检索文档的标题
IsModified 如果文档包含未保存的数据就返回非零值
SetModifiedFlag 设置或清除文档中已修改的标志,该标志说明文档是否包含没有保存的数据
UpdateAllView 通过调用每个视图的OnUpdate函数来更新与文档关联的所有视图
函数

这里面最常用的也就是SetModifyFlag和UpAllView两个函数。每次修改了文档数据之后都要调用SetModifyFlag,此函数在文档对象内设置一个标志告诉MFC文档包含未保存的数据,并允许MFC在关闭文档之前提示用户该文档含有未保存的数据。UpdateAllViews调用每个视图的OnUpdate函数,其默认操作是使视图无效并实现重绘。【CDocument在Afxwin.h中被声明为CView的友元】
CDocument类中也包含许多常用的虚函数,下面仅列举举个最常用、最频繁被翻盖的虚函数:
函数 说明
OnNewDocument 在新文档被创建时主结构调用。覆盖是为了
每次创建新文档时都对文档对象应用专门的初始化
OnOpenDocument 再从磁盘上转载文档时有主结构调用
DeleteContents 主结构调用他来删除文档结构,在文档关闭前
释放分配稳当的内存和其他资源
Serialize 主结构调用他在文档和磁盘之间串行化输入或输出

视图对象
由于文档对象的唯一任务是管理应用程序数据,因此视图对象就有两个用途,提供文档的可视化表示,以及将用户输入(特别是鼠标和键盘消息)转换为操作文档数据的命令,这样,文档和试图就完美的结合在了一起,信息在他们之间进行传递。
MFC的CView类定义了视图的基本属性。当然,MFC还包括一组从CView派生的视图类,用来给视图添加功能。例如:CScrollView给视图添加滚动功能,派生的视图类,这里先不在进行介绍。
GetDocument函数:
一个文档可以具备与她联系的多个视图,而一个视图只能属于一个文档。主结构在视图的m_pDocument数据成员中保存了指向相关文档对象的指针,并将该指针提供给视图的GetDocument成员函数使用。就像文档对象可以调用GetFirstViewPosition和GetNextView表示它的视图一样,视图对象也可以使用GetDocument标识出自己的文档
CView可覆盖函数:
函数 说明
OnDraw 被调用来绘制出文档的数据,覆盖是为了绘制文档视图
OnInitialUpdate 视图第一次附加到文档时被调用。覆盖是为了每次
在文档被创建或装载时都初始化视图对象
OnUpdate 在文档的数据已经修改或属兔需要更新的时候被调用。

这里面最重要的虚函数就是OnDraw,每次在试图接收到WM_PAINT消息时,都会调用他。在对话框应用程序中,WM_PAINT消息有OnPaint程序处理,使用CPaintDC对象来完成绘图。在文档/视图结构中,是主程序产生WM_PAINT消息,创建CPantDC对象,进而调用OnDraw函数。
框架窗口对象
我们已经粗略地回顾了应用程序对象、文档对象和视图对象在文档/视图应用程序中起到的作用。相比较之下,框架窗口对象在屏幕上定义了应用程序的实际工作空间,同时呢,也担当了视图的容器。SDI应用程序仅有一个框架窗口CFrameWnd,它被用作应用程序的顶层窗口并用来包含视图。
在文档/视图应用程序的操作中,框架窗口具有很重要的作用。他并不是一个简简单单的窗口!!!事实上,框架窗口是一种智能对象,他在文档/视图应用程序中管理者许多的幕后工作。 例如,MFC的CFrameWnd类提供了OnClose和OnQuerySession处理程序,确保用户有机会在应用程序关闭或Windows关闭之前保存未保存的数据。在框架窗口被缩放时,CFrameWnd还处理最重要的缩放视图的任务。
所以,框架窗口的作用远远不止盛放视图这么简单!

你可能感兴趣的:(Debug)