| |
深入浅出MFC文档/视图架构之文档 |
|
时间: 2006-03-16 来自:天极开发 |
 |
|
1、文档类CDocument
在"文档/视图"架构的MFC程序中,文档是一个CDocument派生对象,它负责存储应用程序的数据,并把这些信息提供给应用程序的其余部分。CDocument类对文档的建立及归档提供支持并提供了应用程序用于控制其数据的接口,类CDocument的声明如下:
///////////////////////////////////////////////////////////////////////////// //
class CDocument is the main document data abstraction class CDocument :
public CCmdTarget { DECLARE_DYNAMIC(CDocument) public: //
Constructors CDocument();
// Attributes public: const
CString& GetTitle() const; virtual void SetTitle(LPCTSTR
lpszTitle); const CString& GetPathName() const; virtual void
SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU =
TRUE);
CDocTemplate* GetDocTemplate() const; virtual BOOL
IsModified(); virtual void SetModifiedFlag(BOOL bModified =
TRUE);
// Operations void AddView(CView* pView); void
RemoveView(CView* pView); virtual POSITION GetFirstViewPosition()
const; virtual CView* GetNextView(POSITION& rPosition)
const;
// Update Views (simple update - DAG only) void
UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint =
NULL);
// Overridables // Special notifications virtual
void OnChangedViewList(); // after Add or Remove view virtual void
DeleteContents(); // delete doc items etc
// File
helpers virtual BOOL OnNewDocument(); virtual BOOL
OnOpenDocument(LPCTSTR lpszPathName); virtual BOOL
OnSaveDocument(LPCTSTR lpszPathName); virtual void
OnCloseDocument(); virtual void ReportSaveLoadException(LPCTSTR
lpszPathName, CException* e, BOOL bSaving, UINT
nIDPDefault); virtual CFile* GetFile(LPCTSTR lpszFileName, UINT
nOpenFlags, CFileException* pError); virtual void
ReleaseFile(CFile* pFile, BOOL bAbort);
// advanced overridables,
closing down frame/doc, etc. virtual BOOL CanCloseFrame(CFrameWnd*
pFrame); virtual BOOL SaveModified(); // return TRUE if ok to
continue virtual void PreCloseFrame(CFrameWnd* pFrame);
//
Implementation protected: // default implementation CString
m_strTitle; CString m_strPathName; CDocTemplate*
m_pDocTemplate; CPtrList m_viewList; // list of views BOOL
m_bModified; // changed since last saved
public: BOOL
m_bAutoDelete; // TRUE => delete document when no more views BOOL
m_bEmbedded; // TRUE => document is being created by OLE
#ifdef
_DEBUG virtual void Dump(CDumpContext&) const; virtual void
AssertValid() const; #endif //_DEBUG virtual
~CDocument();
// implementation helpers virtual BOOL
DoSave(LPCTSTR lpszPathName, BOOL bReplace = TRUE); virtual BOOL
DoFileSave(); virtual void UpdateFrameCounts(); void
DisconnectViews(); void SendInitialUpdate();
// overridables
for implementation virtual HMENU GetDefaultMenu(); // get menu
depending on state virtual HACCEL GetDefaultAccelerator(); virtual
void OnIdle(); virtual void OnFinalRelease();
virtual BOOL
OnCmdMsg(UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO*
pHandlerInfo); friend class CDocTemplate;
protected: //
file menu commands //{{AFX_MSG(CDocument) afx_msg void
OnFileClose(); afx_msg void OnFileSave(); afx_msg void
OnFileSaveAs(); //}}AFX_MSG // mail enabling afx_msg void
OnFileSendMail(); afx_msg void OnUpdateFileSendMail(CCmdUI*
pCmdUI); DECLARE_MESSAGE_MAP() }; | 一个文档可以有多个视图,每一个文档都维护一个与之相关视图的链表(CptrList类型的
m_viewList实例)。CDocument::AddView将一个视图连接到文档上,并将视图的文档指针指向该文档:
void CDocument::AddView(CView*
pView) { ASSERT_VALID(pView); ASSERT(pView->m_pDocument ==
NULL); // must not be already attached ASSERT(m_viewList.Find(pView,
NULL) == NULL); // must not be in
list
m_viewList.AddTail(pView); ASSERT(pView->m_pDocument
== NULL); // must be un-attached pView->m_pDocument =
this;
OnChangedViewList(); // must be the last thing done to the
document }
| CDocument::RemoveView则完成与CDocument::AddView相反的工作:
void CDocument::RemoveView(CView*
pView) { ASSERT_VALID(pView); ASSERT(pView->m_pDocument ==
this); // must be attached to
us
m_viewList.RemoveAt(m_viewList.Find(pView)); pView->m_pDocument
= NULL;
OnChangedViewList(); // must be the last thing done to the
document } | 从CDocument::AddView和CDocument::RemoveView函数可以看出,在与文档关联的视图被移走或新加入时CDocument::OnChangedViewList将被调用:
void CDocument::OnChangedViewList() { // if no more views on
the document, delete ourself // not called if directly closing the
document or terminating the app if (m_viewList.IsEmpty() &&
m_bAutoDelete) { OnCloseDocument(); return; }
//
update the frame counts as
needed UpdateFrameCounts(); } | CDocument::DisconnectViews将所有的视图都与文档"失连":
void CDocument::DisconnectViews() { while
(!m_viewList.IsEmpty()) { CView* pView =
(CView*)m_viewList.RemoveHead(); ASSERT_VALID(pView); ASSERT_KINDOF(CView,
pView); pView->m_pDocument =
NULL; } } | 实际上,类CDocument对视图的管理与类CDocManager对文档模板的管理及CDocTemplate对文档的管理非常类似,少不了的,类CDocument中可遍历对应的视图(出现GetFirstXXX和GetNextXXX两个函数):
POSITION CDocument::GetFirstViewPosition() const { return
m_viewList.GetHeadPosition(); }
CView*
CDocument::GetNextView(POSITION& rPosition)
const { ASSERT(rPosition != BEFORE_START_POSITION); // use
CDocument::GetFirstViewPosition instead ! if (rPosition ==
NULL) return NULL; // nothing left CView* pView =
(CView*)m_viewList.GetNext(rPosition); ASSERT_KINDOF(CView,
pView); return
pView; }
| CDocument::GetFile和CDocument::ReleaseFile函数完成对参数lpszFileName指定文档的打开与关闭操作:
CFile* CDocument::GetFile(LPCTSTR lpszFileName, UINT
nOpenFlags, CFileException* pError) { CMirrorFile* pFile = new
CMirrorFile; ASSERT(pFile != NULL); if
(!pFile->Open(lpszFileName, nOpenFlags, pError)) { delete
pFile; pFile = NULL; } return pFile; }
void
CDocument::ReleaseFile(CFile* pFile, BOOL
bAbort) { ASSERT_KINDOF(CFile, pFile); if
(bAbort) pFile->Abort(); // will not throw an
exception else pFile->Close(); delete
pFile; } | CDocument类的OnNewDocument、OnOpenDocument、OnSaveDocument及OnCloseDocument这一组成员函数用于创建、打开、保存或关闭一个文档。在这一组函数中,上面的CDocument::GetFile和CDocument::ReleaseFile两个函数得以调用:
BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName) { if
(IsModified()) TRACE0("Warning: OnOpenDocument replaces an unsaved
document.\n");
CFileException fe; CFile* pFile =
GetFile(lpszPathName, CFile::modeRead|CFile::shareDenyWrite,
&fe); if (pFile ==
NULL) { ReportSaveLoadException(lpszPathName, &fe,FALSE,
AFX_IDP_FAILED_TO_OPEN_DOC); return
FALSE; }
DeleteContents(); SetModifiedFlag(); // dirty
during de-serialize
CArchive loadArchive(pFile, CArchive::load |
CArchive::bNoFlushOnDelete); loadArchive.m_pDocument =
this; loadArchive.m_bForceFlat = FALSE; TRY { CWaitCursor
wait; if (pFile->GetLength() != 0) Serialize(loadArchive);
// load me loadArchive.Close(); ReleaseFile(pFile,
FALSE); } CATCH_ALL(e) { ReleaseFile(pFile,
TRUE); DeleteContents(); // remove failed
contents
TRY { ReportSaveLoadException(lpszPathName,
e,FALSE,
AFX_IDP_FAILED_TO_OPEN_DOC); } END_TRY DELETE_EXCEPTION(e); return
FALSE; } END_CATCH_ALL
SetModifiedFlag(FALSE); // start
off with unmodified
return TRUE; } |
|
|
|
|
|
|
|
|