| |
深入浅出MFC文档/视图架构之文档模板 |
|
时间: 2006-03-15 来自:天极开发 |
 |
|
CDocTemplate类的AddDocument、RemoveDocument成员函数使得CDocument* pDoc参数所指向的文档归属于本文档模板(通过将this指针赋值给pDoc所指向CDocument对象的m_pDocTemplate成员变量)或脱离与本文档模板的关系:
void CDocTemplate::AddDocument(CDocument* pDoc) { ASSERT_VALID(pDoc); ASSERT(pDoc->m_pDocTemplate == NULL); // no template attached yet pDoc->m_pDocTemplate = this; } void CDocTemplate::RemoveDocument(CDocument* pDoc) { ASSERT_VALID(pDoc); ASSERT(pDoc->m_pDocTemplate == this); // must be attached to us pDoc->m_pDocTemplate = NULL; } | 而CDocTemplate类的CreateNewDocument成员函数则首先调用CDocument运行时类的CreateObject函数创建一个CDocument对象,再调用AddDocument成员函数将其归属于本文档模板类:
CDocument* CDocTemplate::CreateNewDocument() { // default implementation constructs one from CRuntimeClass if (m_pDocClass == NULL) { TRACE0("Error: you must override CDocTemplate::CreateNewDocument.\n"); ASSERT(FALSE); return NULL; } CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject(); if (pDocument == NULL) { TRACE1("Warning: Dynamic create of document type %hs failed.\n",m_pDocClass->m_lpszClassName); return NULL; } ASSERT_KINDOF(CDocument, pDocument); AddDocument(pDocument); return pDocument; } | 文档类对象由文档模板类构造生成,单文档模板类CSingleDocTemplate只能生成一个文档类对象,并用成员变量 m_pOnlyDoc 指向该对象;多文档模板类可以生成多个文档类对象,用成员变量 m_docList 指向文档对象组成的链表。
CSingleDocTemplate的构造函数、AddDocument及RemoveDocument成员函数都在CDocTemplate类相应函数的基础上增加了对m_pOnlyDoc指针的处理:
CSingleDocTemplate::CSingleDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass) : CDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass) { m_pOnlyDoc = NULL; } void CSingleDocTemplate::AddDocument(CDocument* pDoc) { ASSERT(m_pOnlyDoc == NULL); // one at a time please ASSERT_VALID(pDoc);
CDocTemplate::AddDocument(pDoc); m_pOnlyDoc = pDoc; } void CSingleDocTemplate::RemoveDocument(CDocument* pDoc) { ASSERT(m_pOnlyDoc == pDoc); // must be this one ASSERT_VALID(pDoc);
CDocTemplate::RemoveDocument(pDoc); m_pOnlyDoc = NULL; } | 同样,CMultiDocTemplate类的相关函数也需要对m_docList所指向的链表进行操作(实际上AddDocument和RemoveDocument成员函数是文档模板管理其所包含文档的函数):
// CMultiDocTemplate document management (a list of currently open documents) void CMultiDocTemplate::AddDocument(CDocument* pDoc) { ASSERT_VALID(pDoc);
CDocTemplate::AddDocument(pDoc); ASSERT(m_docList.Find(pDoc, NULL) == NULL); // must not be in list m_docList.AddTail(pDoc); } void CMultiDocTemplate::RemoveDocument(CDocument* pDoc) { ASSERT_VALID(pDoc);
CDocTemplate::RemoveDocument(pDoc); m_docList.RemoveAt(m_docList.Find(pDoc)); } | 由于CMultiDocTemplate类可包含多个文档,依靠其成员函数GetFirstDocPosition和GetNextDoc完成对文档链表m_docList的遍历:
POSITION CMultiDocTemplate::GetFirstDocPosition() const { return m_docList.GetHeadPosition(); } CDocument* CMultiDocTemplate::GetNextDoc(POSITION& rPos) const { return (CDocument*)m_docList.GetNext(rPos); } | 而CSingleDocTemplate的这两个函数实际上并无太大的意义,仅仅是MFC要玩的某种"招数",这个"招数"高明吗?相信看完MFC的相关源代码后你或许不会这么认为,实际上CSingleDocTemplate的GetFirstDocPosition、GetNextDoc函数仅仅只能判断m_pOnlyDoc的是否为NULL:
POSITION CSingleDocTemplate::GetFirstDocPosition() const { return (m_pOnlyDoc == NULL) ? NULL : BEFORE_START_POSITION; }
CDocument* CSingleDocTemplate::GetNextDoc(POSITION& rPos) const { CDocument* pDoc = NULL; if (rPos == BEFORE_START_POSITION) { // first time through, return a real document ASSERT(m_pOnlyDoc != NULL); pDoc = m_pOnlyDoc; } rPos = NULL; // no more return pDoc; } | 笔者认为,MFC的设计者们将GetFirstDocPosition、GetNextDoc作为基类CDocTemplate的成员函数是不合理的,一种更好的做法是将GetFirstDocPosition、GetNextDoc移至CMultiDocTemplate派生类。
CDocTemplate还需完成对其对应文档的关闭与保存操作:
BOOL CDocTemplate::SaveAllModified() { POSITION pos = GetFirstDocPosition(); while (pos != NULL) { CDocument* pDoc = GetNextDoc(pos); if (!pDoc->SaveModified()) return FALSE; } return TRUE; } void CDocTemplate::CloseAllDocuments(BOOL) { POSITION pos = GetFirstDocPosition(); while (pos != NULL) { CDocument* pDoc = GetNextDoc(pos); pDoc->OnCloseDocument(); } } |
|
|
|
|
|
|
|
|