MFC文档视图(二)

 一, 在单文档或者是多文档中,有默认的菜单,这里是这些菜单项默认处理,如下:

菜单内容

命令项ID

默认的处理函数

预有关联

File

 

 

 

New

ID_FILE_NEW

CWinApp::OnFileNew

No

Open

ID_FILE_OPEN

CWinApp::OnFileOpen

No

Close(MDI ONLY)

ID_FILE_CLOSE

CDocumemt::OnFileClose

Yes

Save

ID_FILE_SAVE

CDocument:OnFileSave

Yes

Save As

ID_FILE_SAVEAS

CDocument::OnFileSaveAs

Yes

Print

ID_FILE_PRINT

CView::OnFilePrint

No

Print Pre&view

ID_FILE_PRINT_PREVIEW

CView::OnFilePrintPreview

No

Print Setup

ID_FILE_PRINT_SETUP

CWinApp::OnFilePrintSetup

No

“Recent File Name”

ID_FILE_MRU_FILE1~4

CWinApp::OnOpenRecentFile

Yes

Exit

ID_APP_EXIT

CWinApp::OnFileExit

Yes

Edit

 

 

 

Undo

ID_EDIT_UNDO

None

 

Cut

ID_EDIT_CUT

None

 

Copy

ID_EDIT_COPY

None

 

Paste

ID_EDIT_PASTE

None

 

View

 

 

 

Toolbar

ID_VIEW_TOOLBAR

FrameWnd::OnBarCheck

Yes

Status Bar

ID_VIEW_STATUS_BAR

FrameWnd::OnBarCheck

Yes

Window(MDI only)

 

 

 

New Window

ID_WINDOW_NEW

MDIFrameWnd::OnWindowNew

Yes

Cascade

ID_WINDOW_CASCADE

MDIFrameWnd::OnWindowCmd

Yes

Tile

ID_WINDOW_TILE_HORZ

MDIFrameWnd::OnWindowCmd

Yes

Arrange Icons

ID_WINDOW_ARRANGE

MDIFrameWnd::OnWindowCmd

Yes

Help

 

 

 

About AppName

ID_APP_ABOUT

None

 

上图的最后一个字段“是否预有关联”,如果是Yes,意指只要你的菜单中有此命令项,当它被点击,自然就会引发命令处理程序,应用程序不需要再任何类的Message Map中拦截此命令消息,如果是No,则表示你必须在应用程序中拦截此消息,例如:

BEGIN_MESSAGE_MAP(CSingleApp, CWinApp)
 ON_COMMAND(ID_APP_ABOUT, &CSingleApp::OnAppAbout)
 // 基于文件的标准文档命令
 ON_COMMAND(ID_FILE_NEW, &CWinApp::OnFileNew)
 ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)
 // 标准打印设置命令
 ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()

 

 

二,[FILE/OPEN],[FILE/NEW]的实现过程,如下图:

MFC文档视图(二)_第1张图片

[FILE/NEW]具体如下:

1,CWinApp::OnFileOnew

void CWinApp::OnFileNew()
{
      if (m_pDocManager != NULL)
             m_pDocManager->OnFileNew();
}

 

2:CDocManager::OnFileNew()

void CDocManager::OnFileNew()
{
 if (m_templateList.IsEmpty()){return;}

 CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();
 if (m_templateList.GetCount() > 1)  //多个CDocTemplate弹出对话框让用户选择
 {
  INT_PTR nID = dlg.DoModal();
  if (nID == IDOK)
   pTemplate = dlg.m_pSelectedTemplate;
  else
   return;     // none - cancel operation
 }

 //..............
 pTemplate->OpenDocumentFile(NULL);
}

 

3(1)单文档:CSingleDocTemplate::OpenDocumentFile

CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
 BOOL bMakeVisible)
{
 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;
  pFrame = (CFrameWnd*)AfxGetMainWnd();
 }
 else //否则创建一个新的文档
 {
  pDocument = CreateNewDocument();
  bCreated = TRUE;
 }

 if (pFrame == NULL) //第一次创建Frame
 {
  ASSERT(bCreated);
  pFrame = CreateNewFrame(pDocument, NULL);
 }

 //[FILE/NEW]
 if (lpszPathName == NULL)
 {
  pDocument->OnNewDocument()
 }
 else   //[FILE/OPEN]
 {//如果打开文件失败,创建一个新的Document
  if (!pDocument->OnOpenDocument(lpszPathName))
  {
    pDocument->OnNewDocument()
  }
  pDocument->SetPathName(lpszPathName);
 }

 CWinThread* pThread = AfxGetThread();
 ASSERT(pThread);
 if (bCreated && pThread->m_pMainWnd == NULL)
 {
  pThread->m_pMainWnd = pFrame;
 }

 InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
 return pDocument;
}

 

4.创建文档:CDocTemplate::CreateNewDocument()

CDocument* CDocTemplate::CreateNewDocument()
{//动态创建
 CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject();
 AddDocument(pDocument);
 return pDocument;
}

 

5.创建Frame:CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)

CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)
{

 ASSERT(m_nIDResource != 0); // must have a resource ID to load from
 CCreateContext context;
 context.m_pCurrentFrame = pOther;
 context.m_pCurrentDoc = pDoc;
 context.m_pNewViewClass = m_pViewClass;
 context.m_pNewDocTemplate = this;

 CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();
 // 从资源里创建新的Frame
 pFrame->LoadFrame(m_nIDResource,WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,NULL, &context)
 return pFrame;
}

 

6.CFrameWnd::LoadFrame

BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,CWnd* pParentWnd, CCreateContext* pContext)
{
 // only do this once
 ASSERT_VALID_IDR(nIDResource);
 ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);

 Create(lpszClass, strTitle, dwDefaultStyle, rectDefault,pParentWnd, ATL_MAKEINTRESOURCE(nIDResource), 0L, pContext);
 
 //......

 return TRUE;
}
随着Create调用,会发出WM_CREATE消息,随后如下:

CFrameWnd::OnCreate-->CFameWnd::OnCreateHelper-->CFrameWnd::OnCreateClient(重载它可实现多个视图显示)

-->CreateView

CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID)
{
 //动态创建
 CWnd* pView = (CWnd*)pContext->m_pNewViewClass->CreateObject();
 //创建窗口
 pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,CRect(0,0,0,0), this, nID, pContext)
 //...........
 return pView;
}

 

7.新的文档内部操作初始化,可以重载添加需要的文档初始化:CDocument::OnNewDocument()

BOOL CDocument::OnNewDocument()
{
 DeleteContents();
 m_strPathName.Empty();      // no path name yet
 SetModifiedFlag(FALSE);     // make clean
 return TRUE;
}

 

8.新的文档根据文件初始化CDocument::OnOpenDocument(LPCTSTR lpszPathName)可重载添加文档初始化信息

BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName)
{
 //打开文件
 CFileException fe;
 CFile* pFile = GetFile(lpszPathName,CFile::modeRead|CFile::shareDenyWrite, &fe);

 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);     // 序列化
  loadArchive.Close();
  ReleaseFile(pFile, FALSE);
 }
 CATCH_ALL(e)
 {
  ReleaseFile(pFile, TRUE);
  DeleteContents();   // remove failed contents
 }
 END_CATCH_ALL

 SetModifiedFlag(FALSE);     // start off with unmodified

 return TRUE;
}

9.删除文档处理(重载添加自己的处理):CDocument::DeleteContents()

void CDocument::DeleteContents()
{
}

 

10.CDocTemplate::InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc,BOOL bMakeVisible)

void CDocTemplate::InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc,BOOL bMakeVisible)
{
 // just delagate to implementation in CFrameWnd
 pFrame->InitialUpdateFrame(pDoc, bMakeVisible);
}

 

11.CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible)

void CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible)
{
 // 如果Frame没有Active视图,设置为第一个
 CView* pView = NULL;
 if (GetActiveView() == NULL)
 {
  CWnd* pWnd = GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE);
  if (pWnd != NULL && pWnd->IsKindOf(RUNTIME_CLASS(CView)))
  {
   pView = (CView*)pWnd;
   SetActiveView(pView, FALSE);
  }
 }

 if (bMakeVisible)
 {
  //向这个Frame的所有视图发送WM_INITIALUPDATE消息
  SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
  //根据ON_MESSAGE_VOID(WM_INITIALUPDATE, CView::OnInitialUpdate),所有View都会调用OnInitialUpdate
  //这是View初始化的地方。
 }

 //.......
}

 

3(2)多文档:CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible)

CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible)
{
 CDocument* pDocument = CreateNewDocument();    //创建文档
 CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL);   //创建Frame

 //[FILE/NEW]
 if (lpszPathName == NULL)
 {
  if (!pDocument->OnNewDocument())
  {
   pFrame->DestroyWindow();
   return NULL;
  }
  m_nUntitledCount++;
 }
 else  //[FILE/OPEN]
 {
  // 打开已存在的文档
  if (!pDocument->OnOpenDocument(lpszPathName))
  {
   pFrame->DestroyWindow();
   return NULL;
  }
  pDocument->SetPathName(lpszPathName);
 }

 InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
 return pDocument;
}

 

[FILE/OPEN]

和[FILE/NEW]不同之处在于:

void CDocManager::OnFileOpen()
{
 // 弹出对话框选择文件
 CString newName;
 if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,
   OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, NULL))
  return;


 AfxGetApp()->OpenDocumentFile(newName);
}

 

CDocument*  CWinApp::OpenDocumentFile(LPCSTR lpszFileName)

{

  ASSERT(m_pDocManager != NULL)

  //回到了和[FILE/OPEN]一样的地方

  return m_pDocManager->OpenDocumentFile(lpszFileName);

}

 

在程序一运行是通过命令行信息类来处理的。

BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)

{

  AfxGetApp()->OnCmgMsg(ID_FILE_NEW,0,NULL,NULL);

  //.......

}

你可能感兴趣的:(File,command,null,Class,文档,mfc)