MfC打开过程详解及应用

来源:互联网 发布:南方cass软件多少钱 编辑:程序博客网 时间:2024/06/07 02:17

本文主要介绍:在MFC中,菜单打开命令的响应过程。

一、MFC打开命令的响应过程:

File->Open 对应的ID为ID_FILE_OPEN,其响应过程如下:

注:如果自己已将ID_FLIE_OPEN在MFC中重载了,则会直接响应重载函数,不会按以下过程响应。

1.点击File->Open,首先响应的函数为: CWinApp::OnFileOpen(),其函数原型为:

void CWinApp::OnFileOpen(){ASSERT(m_pDocManager != NULL);        m_pDocManager->OnFileOpen();}

2.由上面的程序可知,接着调用的是: CDocManager::onFileOpen(),该函数功能是:显示打开文件的对话框,并获取文件的路径,其函数原型为:

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}

3.接着调用函数: CWinApp::OpenDocumentFile(LPCTSTR lpszFileName),其函数原型为:
CDocument* CWinApp::OpenDocumentFile(LPCTSTR lpszFileName){    ASSERT(m_pDocManager != NULL);    return m_pDocManager->OpenDocumentFile(lpszFileName);}

4.再调用函数: CDocManager::OpenDocumentFile(LPCTSTR 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;       lstrcpyn(szTemp, lpszFileName, _MAX_PATH);       LPTSTR lpszLast = _tcsrchr(szTemp, '"');       if (lpszLast != NULL)              *lpszLast = 0;         AfxFullPath(szPath, szTemp);       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)                            pFrame->ActivateFrame();                     else                            TRACE0("Error: Can not find a frame for document to activate.\n");                     CFrameWnd* pAppFrame;                     if (pFrame != (pAppFrame = (CFrameWnd*)AfxGetApp()->m_pMainWnd))                     {                            ASSERT_KINDOF(CFrameWnd, pAppFrame);                            pAppFrame->ActivateFrame();                     }              }              else              {                     TRACE0("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);}
5.调用函数:CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible),该函数是多文档打开函数,先创建文档的框架窗口,然后判断路径是否为空,如果为空,则重新设置文档路径;最后,调用InitialUpdateFrame显示框架窗口。其原型为:

CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible){       CDocument* pDocument = CreateNewDocument();       if (pDocument == NULL)       {              TRACE0("CDocTemplate::CreateNewDocument returned NULL.\n");              AfxMessageBox(AFX_IDP_FAILED_TO_CREATE_DOC);              return NULL;       }       ASSERT_VALID(pDocument);       BOOL bAutoDelete = pDocument->m_bAutoDelete;       pDocument->m_bAutoDelete = FALSE;   // don't destroy if something goes wrong       CFrameWnd* 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;       }       ASSERT_VALID(pFrame);       if (lpszPathName == NULL)       {              // create a new document - with default document name              SetDefaultTitle(pDocument);              // avoid creating temporary compound file when starting up invisible              if (!bMakeVisible)                     pDocument->m_bEmbedded = TRUE;              if (!pDocument->OnNewDocument())              {                     // user has be alerted to what failed in OnNewDocument                     TRACE0("CDocument::OnNewDocument returned FALSE.\n");                     pFrame->DestroyWindow();                     return NULL;              }              // it worked, now bump untitled count              m_nUntitledCount++;       }       else       {              // open an existing document              CWaitCursor wait;              if (!pDocument->OnOpenDocument(lpszPathName))              {                     // user has be alerted to what failed in OnOpenDocument                     TRACE0("CDocument::OnOpenDocument returned FALSE.\n");                     pFrame->DestroyWindow();                     return NULL;              }              pDocument->SetPathName(lpszPathName);       }       InitialUpdateFrame(pFrame, pDocument, bMakeVisible);       return pDocument;}
6.最后调用函数:CDocument::OnOpenDocument(LPCTSTR lpszPathName),该函数一般在“***Doc.cpp”中重载(*** 为工程名),因为不同的文件打开的过程不同,所以可以根据需求,在“***Doc.cpp”中改写OnOpenDocument(LPCTSTR lpszPathName)函数,从而打开相应的文件。其默认生成原型为:

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;}
二、总结

通过上述介绍,MFC打开命令的响应过程如下:

         1.首先调用CWinApp::OnFileOpen(),该函数调用CDocManager::OnFileOpen()函数;

         2.CDocManager::OnFileOpen()显示打开文件的对话框,并获取文件的路径,然后该函数调用CWinApp::OpenDocumentFile(LPCTSTR lpszFileName)函数;

         3.CWinApp::OpenDocumentFile(LPCTSTR lpszFileName)函数直接调用CDocManager::OpenDocumentFile(LPCTSTR lpszFileName)函数;

         4.CDocManager::OpenDocumentFile(LPCTSTR lpszFileName)函数遍历文档模板,对每个文档进行匹配,若该文件已经在某个文档中打开,则会激活该文档视图,否则用匹配的文档模板,调用CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible)函数;

         5.CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible)函数先创建文档的框架窗口,然后判断路径是否为空,如果为空,则重新设置文档路径;接着,调用InitialUpdateFrame显示框架窗口,最后调用CDocument::OnOpenDocument(LPCTSTR lpszPathName)函数;

         6.CDocument::OnOpenDocument(LPCTSTR lpszPathName)函数一般在“***Doc.cpp”中重载(*** 为工程名),因为不同的文件打开的过程不同,所以可以根据需求,在“***Doc.cpp”中改写OnOpenDocument(LPCTSTR lpszPathName)函数,从而打开相应的文件。

三、运用

由于打开命令的响应过程,是一系列函数依次调用,因此,可以调用其中的一个环节,来打开文件。以打开图片为例,介绍一下应用:

在打开文件时,弹出的对话框默认的文件“所有文件(*.*)”,如下图:


有时候我们需要打开特定的文件类型,如BMP、Jpg、Tif等类型,即需要弹出下面的对话框:


该功能实现的过程如下:(***代表工程名)

1.在“***.cpp”中重载ID_FILE_OPEN的响应函数OnFileOpen() ,即对ID_FILE_OPEN在C***App的类中添加一个响应函数,函数名为OnFileOpen();

注:如果ID_FILE_OPEN已经重载为:ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen),要把这行代码屏蔽,不然点击打开时,仍默认原来的响应,不会响应自己新重载的函数。

2.编写C***App::OnFileOpen()函数:

void CMyIMGApp::OnFileOpen() {// TODO: Add your command handler code hereCString strOpenFilter = "所有文件(*.*)|*.bmp; *.dib; *.gif; *.jpg; *.jpe; *.jpeg; *.tif; *.tiff; *.raw|位图文件 (*.bmp;*.dib)|*.bmp; *.dib|GIF文件 (*.gif)|*.gif|JPEG文件 (*.jpg;*.jpe;*.jpeg)|*.jpg; *.jpe; *.jpeg|TIFF文件 (*.tif;*.tiff)|*.tif; *.tiff|RAW文件(*.raw)|*.raw|";CFileDialog FileDlg(TRUE, "*.bmp", NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, strOpenFilter);if (FileDlg.DoModal() == IDOK)OpenDocumentFile(FileDlg.m_ofn.lpstrFile);}
该函数是直接调用了上述环节的CWinApp::OpenDocumentFile(LPCTSTR lpszFileName)函数,从而实现文件的打开。

说明:点击打开菜单时,直接的响应函数是自己重载后的函数,通过重载只是改变了前两个环节,最后通过调用OpenDocumentFile(LPCTSTR lpszFileName)函数,使后面函数依次被调用。







0 0
原创粉丝点击