科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件深入浅出MFC文档/视图架构之文档

深入浅出MFC文档/视图架构之文档

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在"文档/视图"架构的MFC程序中,文档是一个CDocument派生对象,它负责存储应用程序的数据,并把这些信息提供给应用程序的其余部分。

作者:宋宝华 来源:天极开发 2007年10月16日

关键字: MFC 视图架构 文档

  • 评论
  • 分享微博
  • 分享邮件
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;
}
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章