按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
列和状态列。
回到InitInstance ,执行ShowWindow 显示窗口。
InitInstance 结束,回到AfxWinMain ,执行Run ,进入消息循环。其间的黑盒子已
在上一章的Hello 范例中挖掘过。
消息经由Message Routing 机制,在各类别的Message Map 中寻求其处理例程。
WM_MAND/ID_FILE_OPEN 消息将由CWinApp::OnFileOpen 函数处理。此函数由
MFC 提供,它在显示过【File Open 】对话框后调用Serialize 函数。
我们改写Serialize 函数以进行我们自己的文件读写动作。
WM_MAND/ID_APP_ABOUT 消息将由OnAppAbout 函数处理。
OnAppAbout 函数利用CDialog 的性质很方便地产生一个对话框。
429
…………………………………………………………Page 492……………………………………………………………
第篇 湷觥 FC 程式設計
Document Template 的意义
Document Template 是一个全新的观念。
稍早我已提过Document/View 的概念,它们互为表里。View 本身虽然已经是一个窗口,
其外围却必须再包装一个外框窗口做为舞台。这样的切割其实是为了让View 可以非常独
立地放置于「MDI Document Frame 窗口」或「SDI Document Frame 窗口」或「OLE Document
Frame 窗口」等各种应用之中。也可以说,Document Frame 窗口是View 窗口的一个容
器。资料的内容、资料的表象、以及「容纳资料表象之外框窗口」三者是一体的,换言
之,程序每打开一份文件(资料),就应该产生三份对象:
1。 一份Document 对象,
2。 一份View 对象,
3。 一份CMDIChildWnd 对象(做为外框窗口)
这三份对象由一个所谓的Document Template 对象来管理。让这三份对象产生关系的关
键在于CMultiDocTemplate:
BOOL CScribbleApp::InitInstance()
{
。。。
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_SCRIBTYPE;
RUNTIME_CLASS(CScribbleDoc);
RUNTIME_CLASS(CChildFrame);
RUNTIME_CLASS(CScribbleView));
AddDocTemplate(pDocTemplate);
。。。
}
如果程序支持不同的资料格式(例如一为TEXT 一为BITMAP ),那么就需要不同的
Document Template :
430
…………………………………………………………Page 493……………………………………………………………
第7章 簡單而完整:MFC 骨幹程式
BOOL CMyWinApp::InitInstance()
{
。。。
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_TEXTTYPE;
RUNTIME_CLASS(CTextDoc);
RUNTIME_CLASS(CChildFrame);
RUNTIME_CLASS(CTextView));
AddDocTemplate(pDocTemplate);
pDocTemplate = new CMultiDocTemplate(
IDR_BMPTYPE;
RUNTIME_CLASS(CBmpDoc);
RUNTIME_CLASS(CChildFrame);
RUNTIME_CLASS(CBmpView));
AddDocTemplate(pDocTemplate);
。。。
}
这其中有许多值得讨论的地方,而CMultiDocTemplate 的构造式参数透露了一些端倪:
CMultiDocTemplate::CMultiDocTemplate(UINT nIDResource;
CRuntimeClass* pDocClass;
CRuntimeClass* pFrameClass;
CRuntimeClass* pViewClass);
1。 nIDResource :这是一个资源ID ,表示此一文件类型(文件格式)所使用的资源。
本例为IDR_SCRIBTYPE,在RC 档中代表多种资源(不同种类的资源可使用
相同的ID ):
IDR_SCRIBTYPE ICON DISCARDABLE 〃resScribbleDoc。ico〃
IDR_SCRIBTYPE MENU PRELOAD DISCARDABLE
{ 。。。 }
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
IDR_MAINFRAME 〃Scribble Step0〃
IDR_SCRIBTYPE 〃nScribnScribnScribble Files (*。scb)n。SCBn
Scribble。DocumentnScrib Document〃
END
原码太长;我把它截为两半;实际上是一整行。有七个子字符串各以'n'
分隔。这些子字符串完整描述文件的类型。第一个子字符串于MDI 程序
中用不着,故本例省略(成为空字符串)。
431
…………………………………………………………Page 494……………………………………………………………
第篇 湷觥 FC 程式設計
其中的ICON 是文件窗口被最小化之后的图标;MENU 是当程序存在有任何文件
窗口时所使用的菜单(如果没有开启任何文件窗口,菜单将是另外一套,稍后再述)。
至于字符串表格(STRINGTABLE )中的字符串,稍后我有更进一步的说明。
2。 pDocClass 。这是一个指针,指向Document 类别( 衍生自CDocument)之
「CRuntimeClass 对象」。
3。 pFrameClass 。这是一个指针,指向Child Frame 类别(衍生自CMDIChildWnd)
之「CRuntimeClass 对象」。
4。 pViewClass 。这是一个指针,指向View 类别(衍生自CView)之「CRuntimeClass
对象」。
CRuntimeClass
我曾经在第3章「自制RTTI 」一节解释过什么是CRuntimeClass。它就是「类别型
录网」串行中的元素类型。任何一个类别只要在声明时使用DECLARE_DYNAMIC 或
DECLARE_DYNCREATE 或DECLARE_SERIAL 宏,就会拥有一个静态的(static )
CRuntimeClass 内嵌对象。
好,你看,Document Template 接受了三种类别的CRuntimeClass 指针,于是每当使用者
打开一份文件,Document Template 就能够根据「类别型录网」(第3章所述),动态生
成出三个对象(document 、view 、document frame window )。如果你不记得MFC 的动态
生成是怎么一回事儿,现在正是复习第3章的时候。我将在第8章带你实际看看
Document Template 的内部动作。
前面曾提到,我们在CMultiDocTemplate 构造式的第一个参数置入IDR_SCRIBTYPE,
代表RC 文件中的菜单(MENU )、图标(ICON )、字符串(STRING )三种资源,其中又
以字符串资源大有学问。这个字符串以'n' 分隔为七个子字符串,用以完整描述文件类型。七
个子字符串可以在AppWizard 的步骤四的【Advanced Options 】对话框中指定:
432
…………………………………………………………Page 495……………………………………………………………
第7章 簡單而完整:MFC 骨幹程式
RC 文件中的字符串资源
IDR_MAINFRAME ::
::
〃Scribble Step0〃
(
IDR_SCRIBTYPE 7 个 子 字 串 ):
((
n
Scribn
Scribn
Scribble Files (*。scb)n
。SCBn
Scribble。Documentn
Scrib Document
每一个子字符串都可以在程序进行过程中取得,只要调用CDocTemplate::GetDocString 并
在其第二参数中指定索引值(1~7)即可,但最好是以CDocTemplate 所定义的七个常数
代替没有字面意义的索引值。下面就是CDocTemplate 的7个常数定义:
// in AFXWIN。H
class CDocTemplate : public CCmdTarget
{
。。。
enum DocStringIndex
{
wi