友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
深入浅出MFC第2版(PDF格式)-第84部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
窗口?你知道,有时候机能与机能之间要有点黏又不太黏才好,把UI 管理机能隔离出来,
可以降低彼此之间的依存性,也可以使机能重复使用于各种场合如SDI、MDI 、OLE in…place
editing (即地编辑)之中。如此一来View 的弹性也会大一些。
Document Template
MFC 把Document/View/Frame 视为三位一体。可不是吗!每当使用者欲打开(或新增)
一份文件,程序应该做出Document 、View 、Frame 各一份。这个「三口组」成为一个
运作单元,由所谓的Document Template 掌管。MFC 有一个CDocTemplate 负责此事。
它又有两个衍生类别,分别是CMultiDocTemplate 和CSingleDocTemplate。
所以我在上一章说了,如果你的程序能够处理两种数据类型,你必须制造两个Document
Template 出来,并使用AddDocTemplate 函数将它们一一加入系统之中。这和程序是不
是MDI 并没有关系。如果你的程序支持多种数据类型,但却是个SDI,那只不过表示
你每次只能开启一份文件罢了。
但是,逐渐地,MDI 这个字眼与它原来的意义有了一些出入(要知道,这个字眼早在SDK
时代即有了)。因此,你可能会看到有些书籍这么说:『MDI 程序使用CMultiDocTemplate,
SDI 程序使用CSingleDocTemplate』,那并不是很精准。
CDocTemplate 是个抽象类别,定义了一些用来处理「Document/View/Frame 三口组」的
基础函数。
459
…………………………………………………………Page 522……………………………………………………………
第篇 深入 MFC 程式設計
CDocTemplate 管理CDocument / CView / CFrameWnd
好,我们说Document Template 管理「三口组」,谁又来管理Document Template 呢?
答案是CWinApp。下面就是InitInstance 中应有的相关作为:
BOOL CScribbleApp::InitInstance()
{
。。。
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_SCRIBTYPE;
RUNTIME_CLASS(CScribbleDoc);
RUNTIME_CLASS(CChildFrame);
RUNTIME_CLASS(CScribbleView));
AddDocTemplate(pDocTemplate);
。。。
}
想一想文件是怎么开启的:使用者选按【File/New 】或【File/Open 】(前者开启一份空文
件,后者读档放到文件中),然后在View 窗口内展现出来。我们很容易误以为是CWinApp
直接产生Document :
BEGIN_MESSAGE_MAP(CScribbleApp; CWinApp)
ON_MAND(ID_APP_ABOUT; OnAppAbout)
ON_MAND(ID_FILE_NEW; CWinApp::OnFileNew)
ON_MAND(ID_FILE_OPEN; CWinApp::OnFileOpen)
ON_MAND(ID_FILE_PRINT_SETUP; CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
其实才不,是Document Template 的杰作:
460
…………………………………………………………Page 523……………………………………………………………
第8章 Document…View 深入探討
【 】 【 】
File/New File/Open
CWinApp 选择适当 的Document Template
CMyDoc
构造Document 对象
CMyView
CChildFrame 构造View 对象 Dynamic Creation
构造Frame
窗口对象
产生Frame 窗口 产生View 窗口
如果是【File/Open】 注意:或许你搞不清楚“构造View 对象”和
读档 “产生View 窗口”的关系。是这样的,View
窗口就是道道地地的Windows 窗口,而为了
将View 窗口初始化
对象管理,MFC 把View 窗口外包一个专属的
C++ 类别,那就是CView。所以当然是先构造
在View 中显示资料
(construct)一个View 对象,再由其构造式
图8…1 Document/View/Frame 的产生 产生(create)对应的View 窗口。Frame 物
件与Frame 窗口的关系亦复如此。
图8…1 的灰色部份,正是Document Template 动态产生「三位一体之
Document/View/Frame 」的行动。下面的流程以及MFC 源代码足以澄清一切疑虑。在
CMultiDocTemplate::OpenDocumentFile (注)出现之前的所有流程,我只做文字叙述,不
显示其源代码。本章稍后有一节「台面下的Serialize 读档奥秘」,则会将每一环节的原
始码呈现在你眼前,让你无所挂虑。
注:如果是SDI 程序,那么就是CSingleDocTemplate::OpenDocumentFile 被调用。但「多」
比「单」有趣,而且本书范例Scribble 程序也使用CMultiDocTemplate,所以我就以此
为说明对象。
CSingleDocTemplate 只支持一种文件类型,所以它的成员变量是:
461
…………………………………………………………Page 524……………………………………………………………
第篇 深入 MFC 程式設計
class CSingleDocTemplate : public CDocTemplate
{
。。。
protected: // standard implementation
CDocument* m_pOnlyDoc;
};
CMultiDocTemplate 支持多种文件类型,所以它的成员变量是:
class CMultiDocTemplate : public CDocTemplate
{
。。。
protected: // standard implementation
CPtrList m_docList;
};
当使用者选按【File/New 】命令项,根据AppWizard 为我们所做的Message Map ,此一
命令由CWinApp::OnFileNew 接手处理。后者调用CDocManager ::OnFileNew,后者再呼
叫CWinApp::OpenDocumentFile,后者再调用CDocManager ::OpenDocumentFile,后者
再调用CMultiDocTemplate::OpenDocumentFile (这是观察MFC 源代码所得结果):
// in AFXWIN。H
class CDocTemplate : public CCmdTarget
{
。。。
UINT m_nIDResource; // IDR_ for frame/menu/accel as well
CRuntimeClass* m_pDocClass; // class for creating new documents
CRuntimeClass* m_pFrameClass; // class for creating new frames
CRuntimeClass* m_pViewClass; // class for creating new views
CString m_strDocStrings; // 'n' separated names
。。。
}
// in DOCMULTI。CPP
CDocument* CMultiDocTemplate::OpenDocumentFile (LPCTSTR lpszPathName;
BOOL bMakeVisible)
{
CDocument* pDocument = CreateNewDocument ();
。。。
CFrameWnd* pFrame = CreateNewFrame (pDocument; NULL);
。。。
if (lpszPathName == NULL)
{
// create a new document with default document name
462
…………………………………………………………Page 525……………………………………………………………
第8章 Document…View 深入探討
。。。
}
else
{
// open an existing document
。。。
}
InitialUpdateFrame(pFrame; pDocument; bMakeVisible);
return pDocument;
}
顾名思义,我们很容易作出这样的联想:CreateNewDocument 动态产生Document ,
CreateNewFrame 动态产生Document Frame 。的确是这样没错,它们利用CRuntimeClass
的CreateObject 做「动态生成」动作:
// in DOCTEMPL。CPP
CDocument* CDocTemplate::CreateNewDocument ()
{
。。。
CDocument* pDocument = (CDocument*)m_pDocClass…》CreateObject ();
。。。
AddDocument(pDocument);
return pDocument;
}
CFrameWnd* CDocTemplate::CreateNewFrame (CDocument* pDoc; CFrameWnd* pOther)
{
// create a frame wired to the specified document
CCreateContext context;
context。m_pCurrentFrame = pOther;
context。m_pCurrentDoc = pDoc;
context。m_pNewViewClass = m_pViewClass;
context。m_pNewDocTemplate = this;
。。。
CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass…》CreateObject ();
。。。
// create new from resource
pFrame…》LoadFrame (m_nIDResource;
WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE; // default frame styles
NULL; &context)
。。。
return pFrame;
}
在CreateNewFrame 函数中, 不仅Frame 被动态生成出来了,其对应窗口也以
463
…………………………………………………………Page 526……………………………………………………………
第篇 深入 MFC 程式設計
LoadFrame 产生出来了。但有两件事情令人不解。第一,我们没有看到View 的动态生
成动作;第二,出现一个奇怪的家伙CCreateContext,而前一个不解似乎能够着落到这
个奇怪家伙的身上,因为CDocTemplate::m_pViewClass 被塞到它的一个字段中。
但是线索似乎已经中断,因为我们已经看不到任何可能的调用动作了。等一等!context 被
用作LoadFrame 的最后一个参数,这意味什么?还记得第六章「CFrameWnd::Create 产
生主窗口(并先注册窗口类别)」那一节提过Create 的最后一个参数吗,正是这context 。
那么,是不是Document Frame 窗口产生之际由于WM_CREATE 的发生而刺激了什么动
作?
虽然其结果是正确的,但这样的联想也未免太天马行空了些。我只能说,经验累积出判
断力!是的,WM_CREATE 引发CFrameWnd::OnCreate 被唤起,下面是相关的调用次序
(经观察MFC 源代码而得知):
CFrameWnd::OnCreate
CFrameWnd::OnCreate
CFrameWnd::OnCreateHelper
CFrameWnd::OnCreateHelper
CFrameWnd::OnCreateClient
CFrameWnd::OnCreateClient
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!