前文我们提到,由于MFC的设计者将CSingleDocTemplate和CMultiDocTemplate的行为未进行规范的区分,它对仅仅对应
一个文档的CSingleDocTemplate也提供了所谓的GetFirstDocPosition、GetNextDoc遍历操作,所以基类CDocTemplate的SaveAllModified和CloseAllDocuments
函数(都是遍历)就可统一CSingleDocTemplate和CMultiDocTemplate两个本身并不相同类的SaveAllModified和CloseAllDocuments行为(实际上,对于CSingleDocTemplate而言,SaveAllModified和CloseAllDocuments中的"All"是没有太大意义的。教室里有
1个老师和N个同学,老师可以对同学们说"所有同学",而学生对老师说"所有老师"相信会被当成神经病)。MFC的设计者们特意使用了"将错就错"的
方法意图简化CSingleDocTemplate和CMultiDocTemplate类的设计,读者朋友可以不认同他们的做法。
CDocTemplate还提供了框架窗口的创建和初始化
函数:
/ // Default frame creation CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc,CFrameWnd* pOther) { if (pDoc != NULL) ASSERT_VALID(pDoc); // create a frame wired to the specified document
ASSERT(m_nIDresource != 0); // must have a resource ID to load from CCreateContext context; context.m_pCurrentFrame = pOther; context.m_pCurrentDoc = pDoc; context.m_pNewViewClass = m_pViewClass; context.m_pNewDocTemplate = this;
if (m_pFrameClass == NULL) { TRACE0("Error: you must override CDocTemplate::CreateNewFrame./n"); ASSERT(false); return NULL; } CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject(); if (pFrame == NULL) { TRACE1("Warning: Dynamic create of frame %hs @L_674_4@./n",m_pFrameClass->m_lpszClassName); return NULL; } ASSERT_KINDOF(CFrameWnd,pFramE);
if (context.m_pNewViewClass == NULL) TRACE0("Warning: creaTing frame with no default view./n");
// create new from resource if (!pFrame->LoadFrame(m_nIDresource,WS_OVERLAPPEDWINDOW | FWS_ADDTOtitlE,// default frame styles NULL,&context)) { TRACE0("Warning: CDocTemplate Couldn't create a frame./n"); // frame will be deleted in PostNcDestroy cleanup return NULL; }
// it worked ! return pFrame; } void CDocTemplate::InitialupdateFrame(CFrameWnd* pFrame,CDocument* pDoc,BOOL bMakeVisiblE) { // just delagate to implementation in CFrameWnd pFrame->InitialupdateFrame(pDoc,bMakeVisiblE); } |
3. CWinApp与CD
OCManager/CDocTemplate类
应用程序CWinApp类对象与CD
OCManager和CDocTemplate类的关系是:CWinApp对象中包含
一个CD
OCManager指针类型的共有数据成员m_pD
OCManager,CWinApp::Ini
Tinstance
函数调用CWinApp::AddDocTemplate
函数向链表m_templateList
添加模板指针(实际上是
调用前文所述CD
OCManager的AddDocTemplate
函数)。另外,CWinApp也提供了GetFirstDocTemplatePosition和GetNextDocTemplate
函数实现来对m_templateList链表进行访问(实际上也是
调用了前文所述CD
OCManager的GetFirstDocTemplatePosition、GetNextDocTemplate
函数)。我们仅摘取CWinApp类声明的一小部分:
class CWinApp : public CWinThread { … CDOCManager* m_pDOCManager;
// Running Operations - to be done on a running application // Dealing with document templates void AddDocTemplate(CDocTemplate* pTemplatE); POSITION GetFirstDocTemplatePosition() const; CDocTemplate* GetNextDocTemplate(POSITION& pos) const;
// Dealing with files virtual CDocument* OpenDocumentFile(LPCTSTR lpszFileName); // open named file void CloseAllDocuments(BOOL bEndSession); // close documents before exiTing
// Command Handlers protected: // map to the following for file new/open afx_msg void OnFileNew(); afx_msg void OnFileopen(); int GetOpenDocumentCount(); … }; |
来看CWinApp派生类CSDIExampleApp(单文档)、CMDIExampleApp(多文档)的Ini
Tinstance成员
函数的例子(仅仅摘取与文档模板相关的部分):
BOOL CSDIExampleApp::IniTinstance() { … CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate(IDR_MAINFRAME,RUNTIME_CLASS(CSDIExampleDoC), RUNTIME_CLASS(CMainFramE),// main SDI frame window RUNTIME_CLASS(CSDIExampleView)); AddDocTemplate(pDocTemplatE); … return TRUE; } BOOL CMDIExampleApp::IniTinstance() { … CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate(IDR_MDIEXATYPE, RUNTIME_CLASS(CMDIExampleDoC), RUNTIME_CLASS(CChildFramE),// custom MDI child frame RUNTIME_CLASS(CMDIExampleView)); AddDocTemplate(pDocTemplatE); … } |
读者朋友,看完本次连载,也许您有许多不明白的地方,这是正常的。因
为其所讲解的
内容与后续几次连载息息相关,我们愈往后看,就会愈加清晰。对于本次连载的
内容,您只需要建立基本的印象。最初的浅尝辄止是为了最终的深入脊髓!
我们试图对MFC的深层机理刨根究底,"拨开云雾见月明"的过程是艰辛的!