MfC打开过程详解及应用

本文主要介绍:在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)函数,从而打开相应的文件。

三、运用

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

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

MfC打开过程详解及应用_第1张图片

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

MfC打开过程详解及应用_第2张图片

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

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 here
	CString 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)函数,使后面函数依次被调用。







你可能感兴趣的:(MFC打开,MFC打开函数,MFC打开响应过程,MFC打开对话框,打开响应函数)