深入浅出MFC第2版(PDF格式)-第93部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
。。。
}
// 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
CFrameWnd::CreateView
CFrameWnd::CreateView
// in WINFRM。CPP
CWnd* CFrameWnd::CreateView(CCreateContext* pContext; UINT nID)
{
。。。
CWnd* pView = (CWnd*)pContext…》m_pNewViewClass…》CreateObject ();
。。。
// views are always created with a border!
pView…》Create (NULL; NULL; AFX_WS_DEFAULT_VIEW;
CRect(0;0;0;0); this; nID; pContext))
。。。
if (afxData。bWin4 && (pView…》GetExStyle() & WS_EX_CLIENTEDGE))
{
464
…………………………………………………………Page 527……………………………………………………………
第8章 Document…View 深入探討
// remove the 3d style from the frame; since the view is
// providing it。
// make sure to recalc the non…client area
ModifyStyleEx(WS_EX_CLIENTEDGE; 0; SWP_FRAMECHANGED);
}
return pView;
}
不仅View 对象被动态生成出来了,其对应的实际Windows 窗口也以Create 函数产生出
来。
正因为MFC 把View 对象的动态生成动作包装得如此诡谲奇险,所以我才在图8…1 中
把「构造View 对象」和「产生View 窗口」这两个动作特别另立一旁:
构造Document 对象
构造View 对象
构造Frame 窗口对象
产生Frame 窗口 产生View 窗口
465
…………………………………………………………Page 528……………………………………………………………
第篇 深入 MFC 程式設計
图8…2 解释CDocTemplate、CDocument、CView、CFrameWnd 之间的关系。下面则是
一份文字整理:
■ CWinApp 拥有一个对象指针:CDocManager* m_pDocManager 。
■ CDocManager 拥有一个指针串行CPtrList m_templateList, 用来维护一系列的
Document Template。一个程序若支持两「种」文件类型,就应该有两份Document
Templates ,应用程序应该在CMyWinApp ::InitInstance 中以AddDocTemplate 将
这些Document Templates 加入由CDocManager 所维护的串行之中。
■ CDocTemplate 拥有三个成员变量, 分别持有Document 、View 、Frame 的
CRumtimeClass 指针,另有一个成员变量m_nIDResource ,用来表示此Document
显现时应该采用的UI 对象。这四份资料应该在CMyWinApp::InitInstance 函数
构造CDocTemplate (注1)时指定之,成为构造式的参数。当使用者欲打开一
份文件(通常是借着【File/Open 】或【File/New 】命令项),CDocTemplate 即
可藉由Document/View/Frame 之CRuntimeClass 指针(注2 )进行动态生成。
注1:在此我们必须有所选择,要不就使用CSingleDocTemplate,要不就使用
CMultiDocTemplate , 两者都是CDocTemplate 的衍生类别。如果你选用
CSingleDocTemplate,它有一个成员变量CDocument* m_pOnlyDoc,亦即它一次只能
打开一份Document 。如果你选用CMultiDocTemplate,它有一个成员变量CPtrList
m_docList,表示它能同时打开多个Documents 。
注2 :关于CRuntimeClass 与动态生成,我在第3章已经以DOS 程序仿真之,本章
稍后亦另有说明。
■ CDocument 有一个成员变量CDocTemplate* m_pDocTemplate,回指其Document
Template;另有一个成员变量CPtrList m_viewList,表示它可以同时维护一系列
的Views 。
■ CFrameWnd 有一个成员变量CView* m_pViewActive ,指向目前正作用中的
Vie。w
■ CView 有一个成员变量CDocument* m_pDocument,指向相关的Document 。
466
…………………………………………………………Page 529……………………………………………………………
第8章 Document…View 深入探討
CWinApp CDocManager
CDocManager* m_pDocManager; CPtrList m_templateList;
My。RC
IDR_SCRIBBTYPE ICON 〃。。。〃
IDR_SCRIBBTYPE MENU Document Template
{ 。。。 } UINT m_nIDResource; Document Template
STRINGTABLE
BEGIN CRuntimeClass* m_pDocClass;
CRuntimeClass* m_pFrameClass;
IDR_SCRIBBTYPE
“。。。n。。。n 。。。n 。。。n 。。。n 。。。n 。。。” CRuntimeClass* m_pViewClass;
END
CDocument* m_pOnlyDoc;
CObject::classCObject CCmdTarget::classCCmdTargetCThreadApp::classCThreadApp
“CObject” “CCmdTarget” “CWinThread” // in CSingleDocTemplate
4 4 4
or
m_pfnConstruct m_pfnConstruct m_pfnConstruct
m_pNextClass m_pNextClass m_pNextClass CPtrList m_docList;
NULL
CFrameWnd::classCFrameWndCWnd::classCWnd CWinApp::classCWinApp // in CMultiDocTemplate
“CFrameWnd” “CWnd” “CWinApp”
12 4 4
m_pfnConstruct m_pfnConstruct m_pfnConstruct