作者:(ECNU)孟庆涛 Email:mqt-2003@163.com
void CMyApp::OnFileNewStudent(){ OpenNewDocument("Studnt");}void CMyApp::OnFileNewTeacher(){ OpenNewDocument("Teachr");}Then add the OpenNewDocument helper function as follows:
BOOL CMyApp::OpenNewDocument(const CString& strTarget){ CString strDocName; CDocTemplate* pSelectedTemplate; POSITION pos = GetFirstDocTemplatePosition(); while (pos != NULL) { pSelectedTemplate = (CDocTemplate*) GetNextDocTemplate(pos); ASSERT(pSelectedTemplate != NULL); ASSERT(pSelectedTemplate->IsKindOf(RUNTIME_CLASS(CDocTemplate))); pSelectedTemplate->GetDocString(strDocName,CDocTemplate::docName); if (strDocName == strTarget) { // from template's // string resource pSelectedTemplate->OpenDocumentFile(NULL); return TRUE; } } return FALSE;}在面向对象程序设计领域中,对象可以被持续,即当程序退出时他们可以被存盘,而当程序重启动时他们又可以被恢复。对象的这种存盘和恢复处理过程就称为“序列化”。
持续文档对象
Serialize
CArchive
CFile
The CArchive object buffers data for the CFile object, and it maintains an internal flag that indicates whether the archive is storing (writing to disk) or loading (reading from disk). Only one active archive is associated with a file at any one time. The application framework takes care of constructing the CFile and CArchive objects, opening the disk file for the CFile object, and associating the archive object with the file. All you have to do (in your Serialize function) is load data from or store data in the archive object. The application framework calls the document’s Serialize function during the File Open and File Save processes(1)CWinApp::OnFileNew
Creating an Empty Document: The CWinApp::OnFileNew Function
开始运行时,CWinApp::ProcessShellCommand会自动调用OnFileNew函数。
After your application class’s InitInstance function calls the AddDocTemplate member function, it calls OnFileNew (indirectly through CWinApp::ProcessShellCommand), another important CWinApp member function. OnFileNew sorts through the web of interconnected class names and does the following:
(2)OnFileOpen
When the MFC Application Wizard generates an application, it maps the File Open menu command to the CWinApp::OnFileOpen member function. When called, this function invokes a sequence of functions to accomplish these steps:
1. Prompts the user to select a file.
2. Calls the virtual function CDocument::OnOpenDocument for the already existing document object. This function opens the file, calls CDocument::DeleteContents, and constructs a CArchive object set for loading. It then calls the document’s Serialize function, which loads data from the archive.
3. Calls the view’s OnInitialUpdate function.
(3)MFC源代码分析:注意:表格左边是新建文件过程,右边是打开文件过程,没分左右的则是二者的功用部分。下面都是MFC后台代码,涉及到序列化问题等。总之,自己品味,其乐无穷。:) | NEW | Open | |
| void CWinApp::OnFileNew() { if (m_pDocManager != NULL) m_pDocManager->OnFileNew(); } | void CWinApp::OnFileOpen() { ASSERT(m_pDocManager != NULL); m_pDocManager->OnFileOpen(); } | |
| void CDocManager::OnFileNew() { if (m_templateList.IsEmpty()) { TRACE(traceAppMsg, 0, "Error: no document templates registered with CWinApp.\n"); AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); return; } CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead(); if (m_templateList.GetCount() > 1) { // more than one document template to choose from // bring up dialog prompting user CNewTypeDlg dlg(&m_templateList); INT_PTR nID = dlg.DoModal(); if (nID == IDOK) pTemplate = dlg.m_pSelectedTemplate; else return; // none - cancel operation } ASSERT(pTemplate != NULL); ASSERT_KINDOF(CDocTemplate, pTemplate); pTemplate->OpenDocumentFile(NULL); // if returns NULL, the user has already been alerted } | void CDocManager::OnFileOpen() { // prompt the user (with all document templates) CString newName; if (!DoPromptFileName(newName, AFX_IDS_OPENFILE, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL)) return; // open cancelled AfxGetApp()->OpenDocumentFile(newName); // if returns NULL, the user has already been alerted } | |
| 无 | CDocument* CWinApp::OpenDocumentFile(LPCTSTR lpszFileName) { ASSERT(m_pDocManager != NULL); return m_pDocManager->OpenDocumentFile(lpszFileName); } | |
| 无 | CDocument* CDocManager::OpenDocumentFile(LPCTSTR lpszFileName) { // find the highest confidence POSITION pos = m_templateList.GetHeadPosition(); CDocTemplate::Confidence bestMatch = CDocTemplate::noAttempt; CDocTemplate* pBestTemplate = NULL; CDocument* pOpenDocument = NULL; TCHAR szPath[_MAX_PATH]; ASSERT(lstrlen(lpszFileName) < _countof(szPath)); TCHAR szTemp[_MAX_PATH]; if (lpszFileName[0] == '\"') ++lpszFileName; lstrcpyn(szTemp, lpszFileName, _MAX_PATH); LPTSTR lpszLast = _tcsrchr(szTemp, '\"'); if (lpszLast != NULL) *lpszLast = 0; if( AfxFullPath(szPath, szTemp) == FALSE ) { ASSERT(FALSE); return NULL; // We won't open the file. MFC requires paths with // length < _MAX_PATH } TCHAR szLinkName[_MAX_PATH]; if (AfxResolveShortcut(AfxGetMainWnd(), szPath, szLinkName, _MAX_PATH)) lstrcpy(szPath, szLinkName); while (pos != NULL) { CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos); ASSERT_KINDOF(CDocTemplate, pTemplate); CDocTemplate::Confidence match; ASSERT(pOpenDocument == NULL); match = pTemplate->MatchDocType(szPath, pOpenDocument); if (match > bestMatch) { bestMatch = match; pBestTemplate = pTemplate; } if (match == CDocTemplate::yesAlreadyOpen) break; // stop here } if (pOpenDocument != NULL) { POSITION pos = pOpenDocument->GetFirstViewPosition(); if (pos != NULL) { CView* pView = pOpenDocument->GetNextView(pos); // get first one ASSERT_VALID(pView); CFrameWnd* pFrame = pView->GetParentFrame() if (pFrame == NULL) TRACE(traceAppMsg, 0, "Error: Can not find a frame for document to activate.\n"); else {pFrame->ActivateFrame(); if (pFrame->GetParent() != NULL) { CFrameWnd* pAppFrame; if (pFrame != (pAppFrame = (CFrameWnd*)AfxGetApp()->m_pMainWnd)) { ASSERT_KINDOF(CFrameWnd, pAppFrame); pAppFrame->ActivateFrame(); } } } } else TRACE(traceAppMsg, 0, "Error: Can not find a view for document to activate.\n"); return pOpenDocument; } if (pBestTemplate == NULL) { AfxMessageBox(AFX_IDP_FAILED_TO_OPEN_DOC); return NULL; } return pBestTemplate->OpenDocumentFile(szPath); } | |
| 1: 单文档模板 CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible) // if lpszPathName == NULL => create new file of this type { CDocument* pDocument = NULL; CFrameWnd* pFrame = NULL; BOOL bCreated = FALSE; // => doc and frame created BOOL bWasModified = FALSE; if (m_pOnlyDoc != NULL) { // already have a document - reinit it pDocument = m_pOnlyDoc; if (!pDocument->SaveModified()) return NULL; // leave the original one pFrame = (CFrameWnd*)AfxGetMainWnd(); ASSERT(pFrame != NULL); ASSERT_KINDOF(CFrameWnd, pFrame); ASSERT_VALID(pFrame); } else { // create a new document pDocument = CreateNewDocument(); //建立一个新的文档对象 ASSERT(pFrame == NULL); // will be created below bCreated = TRUE; } if (pDocument == NULL) { AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); return NULL; } ASSERT(pDocument == m_pOnlyDoc); if (pFrame == NULL) { ASSERT(bCreated); // create frame - set as main document frame BOOL bAutoDelete = pDocument->m_bAutoDelete; pDocument->m_bAutoDelete = FALSE; // don't destroy if something goes wrong pFrame = CreateNewFrame(pDocument, NULL); //在这里建立框架和视图,实现三位一体 pDocument->m_bAutoDelete = bAutoDelete; if (pFrame == NULL) { AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC); delete pDocument; // explicit delete on error return NULL; } } if (lpszPathName == NULL) // 对File/NEW而言 { // create a new document SetDefaultTitle(pDocument); // avoid creating temporary compound file when starting up invisible if (!bMakeVisible) pDocument->m_bEmbedded = TRUE; if (!pDocument->OnNewDocument())//调用前面建立的文档对象的函数,建立新文档 { // user has been alerted to what failed in OnNewDocument TRACE(traceAppMsg, 0, "CDocument::OnNewDocument returned FALSE.\n"); if (bCreated) pFrame->DestroyWindow(); // will destroy document return NULL; } } else //对File/Open而言 { CWaitCursor wait; // open an existing document bWasModified = pDocument->IsModified(); pDocument->SetModifiedFlag(FALSE); // not dirty for open if (!pDocument->OnOpenDocument(lpszPathName)) { // user has been alerted to what failed in OnOpenDocument TRACE(traceAppMsg, 0, "CDocument::OnOpenDocument returned FALSE.\n"); if (bCreated) { pFrame->DestroyWindow(); // will destroy document } else if (!pDocument->IsModified()) { // original document is untouched pDocument->SetModifiedFlag(bWasModified); } else { // we corrupted the original document SetDefaultTitle(pDocument); if (!pDocument->OnNewDocument()) { TRACE(traceAppMsg, 0, "Error: OnNewDocument failed after trying " "to open a document - trying to continue.\n"); // assume we can continue } } return NULL; // open failed } pDocument->SetPathName(lpszPathName); } CWinThread* pThread = AfxGetThread(); ASSERT(pThread); | ||