现在的位置: 首页 > 综合 > 正文

深入浅出MFC“文档/视图”架构(3)――文档

2013年03月04日 ⁄ 综合 ⁄ 共 5657字 ⁄ 字号 评论关闭
 

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::AddViewCDocument::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中可遍历对应的视图(出现GetFirstXXXGetNextXXX两个函数):
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::GetFileCDocument::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;
}

抱歉!评论已关闭.