打开文档的函数CDocument::OnOpenDocument完成的工作包括如下几步:
(1)打开文件对象;
(2)调用DeleteDontents();
(3)建立与此文件对象相关联的CArchive对象;
(4)调用应用程序文档对象的Serialize()函数;
(5)关闭CArchive对象、文件对象。
BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName) { CFileException fe; CFile* pFile = NULL; pFile = GetFile(lpszPathName, CFile::modeCreate |CFile::modeReadWrite | CFile::shareExclusive, &fe);
if (pFile == NULL) { ReportSaveLoadException(lpszPathName, &fe,TRUE, AFX_IDP_INVALID_FILENAME); return FALSE; }
CArchive saveArchive(pFile, CArchive::store | CArchive::bNoFlushOnDelete); saveArchive.m_pDocument = this; saveArchive.m_bForceFlat = FALSE; TRY { CWaitCursor wait; Serialize(saveArchive); // save me saveArchive.Close(); ReleaseFile(pFile, FALSE); } CATCH_ALL(e) { ReleaseFile(pFile, TRUE);
TRY { ReportSaveLoadException(lpszPathName, e,TRUE, AFX_IDP_FAILED_TO_SAVE_DOC); } END_TRY DELETE_EXCEPTION(e); return FALSE; } END_CATCH_ALL SetModifiedFlag(FALSE); // back to unmodified return TRUE; // success } |
保存文档的函数CDocument::OnSaveDocument完成的工作包括如下几步:
(1)创建或打开文件对象;
(2)建立相对应的CArchive对象;
(3)调用应用程序文档对象的序列化函数Serialize();
(4)关闭文件对象、CArchive对象;
(5)设置文件未修改标志。
void CDocument::OnCloseDocument() // must close all views now (no prompting) - usually destroys this { // destroy all frames viewing this document // the last destroy may destroy us BOOL bAutoDelete = m_bAutoDelete; m_bAutoDelete = FALSE; // don't destroy document while closing views while (!m_viewList.IsEmpty()) { // get frame attached to the view CView* pView = (CView*)m_viewList.GetHead(); ASSERT_VALID(pView); CFrameWnd* pFrame = pView->GetParentFrame(); ASSERT_VALID(pFrame);
// and close it PreCloseFrame(pFrame); pFrame->DestroyWindow(); // will destroy the view as well } m_bAutoDelete = bAutoDelete;
// clean up contents of document before destroying the document itself DeleteContents();
// delete the document if necessary if (m_bAutoDelete) delete this; } |
CDocument::OnCloseDocument函数的程序流程为:
(1)通过文档对象所对应的视图,得到显示该文档视图的框架窗口的指针;
(2)关闭并销毁这些框架窗口;
(3)判断文档对象的自动删除变量m_bAutoDelete是否为真,如果为真,则以delete this语句销毁文档对象本身。
实际上,真正实现文档存储和读取(相对于磁盘)的函数是Serialize,这个函数通常会被CDocument的派生类重载(加入必要的代码,用以保存对象的数据成员到CArchive对象以及从CArchive对象载入对象的数据成员状态):
void CExampleDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { // TODO: add storing code here ar << var1 << var2; } else { // TODO: add loading code here var2 >> var1 >> ar; } } |
地球人都知道,文档与视图进行通信的方式是调用文档类的UpdateAllViews函数:
void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint) // walk through all views { ASSERT(pSender == NULL || !m_viewList.IsEmpty()); // must have views if sent by one of them
POSITION pos = GetFirstViewPosition(); while (pos != NULL) { CView* pView = GetNextView(pos); ASSERT_VALID(pView); if (pView != pSender) pView->OnUpdate(pSender, lHint, pHint); } } |
UpdateAllViews函数遍历视图列表,对每个视图都调用其OnUpdate函数实现视图的更新显示。
2.文档的OPEN/NEW
从连载2可以看出,在应用程序类CWinapp的声明中包含文件的New和Open函数:
afx_msg void OnFileNew(); afx_msg void OnFileOpen(); |
而在文档模板管理者类CDocManager中也包含文件的New和Open函数:
virtual void OnFileNew(); virtual void OnFileOpen(); virtual CDocument* OpenDocumentFile(LPCTSTR lpszFileName); // open named file |
而文档模板类CDocTemplate也不例外:
virtual CDocument* OpenDocumentFile( LPCTSTR lpszPathName, BOOL bMakeVisible = TRUE) = 0; // open named file // if lpszPathName == NULL => create new file with this type virtual CDocument* CreateNewDocument(); |
复杂的是,我们在CDocument类中再次看到了New和Open相关函数:
virtual BOOL OnNewDocument(); virtual BOOL OnOpenDocument(LPCTSTR lpszPathName); |
在这众多的函数中,究竟文档的创建者和打开者是谁?"文档/视图"框架程序"File"菜单上的"New"和"Open"命令究竟对应着怎样的函数调用行为?这一切都使我们陷入迷惘!
实际上"文档/视图"框架程序新文档及其关联视图和框架窗口的创建是应用程序对象、文档模板、新创建的文档和新创建的框架窗口相互合作的结果。具体而言,应用程序对象创建了文档模板;文档模板则创建了文档及框架窗口;框架窗口创建了视图。
在用户按下ID_FILE_OPEN及ID_FILE_NEW菜单(或工具栏)命令后,CWinApp(派生)类的OnFileNew、OnFileOpen函数首先被执行,其进行的行为是选择合适的文档模板,如图3.1所示。
 图3.1文档模板的选择 |
实际上,图3.1中所示的"使用文件扩展名选择文档模板"、"是一个文档模板吗?"的行为都要借助于CDocManager类的相关函数,因为只有CDocManager类才维护了文档模板的列表。CDocManager::OnFileNew的行为可描述为:
void CDocManager::OnFileNew() { if (m_templateList.IsEmpty()) { ... return ; } //取第一个文档模板的指针 CDocTemplate *pTemplate = (CDocTemplate*)m_templateList.GetHead(); if (m_templateList.GetCount() > 1) { // 如果多于一个文档模板,弹出对话框提示用户选择 CNewTypeDlg dlg(&m_templateList); int nID = dlg.DoModal(); if (nID == IDOK) pTemplate = dlg.m_pSelectedTemplate; else return ; // none - cancel operation } … //参数为NULL的时候OpenDocument File会新建一个文件 pTemplate->OpenDocumentFile(NULL); } |
之后,文档模板类的virtual CDocument* OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible = TRUE) = 0函数进行文档的创建工作,如果lpszPathName == NULL,是文档New行为;相反,则是Open行为。在创建框架后,文档模板根据是Open还是New行为分别调用CDocument的OnOpenDocument、OnNewDocument函数。图3.2描述了整个过程。
 图3.2文档、框架窗口的创建顺序 |
而图3.3则给出了视图的创建过程。
 图3.3视图的创建顺序 |
图3.1~3.3既描述了文档/视图框架对ID_FILE_OPEN及ID_FILE_NEW命令的响应过程,又描述了文档、框架窗口及视图的创建。的确,是无法单独描述文档的New和Open行为的,因为它和其他对象的创建交错纵横。
相信,随着我们进一步阅读后续连载,会对上述过程有更清晰的认识。 
说明:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。
2/2 首页 上一页 1 2 |