在mfc的单文档的应用程序(Application)设计时,一般是一种文档(Documnet)对应一种视图(View) 。然而在有些时候我需要一种文档用多种视图来展现,具体步骤如下:

我们有两个假设

  • CMyWinApp是该程序的应用程序,并声明和定义在MYWINAPP.H和MYWINAPP.CPP文件中.
  • CNewView是从CView上继承的视图类, 并声明和定义在NEWVIEW.H and NEWVIEW.CPP文件中.
    1.修改应用程序类(Application Class);在MYWINAPP.H加入如下声明
    CView* m_pOldView;
    CView* m_pNewView;
    CView* SwitchView( );
     m_pOldView 和m_pNewView分别指向当前的视图类(新建程序时自动创建的一个视图类)和即将创建的新的视图类,SwitchView函数用于相应用户视图切换操作,具体实现参见下面的步骤。
    在MYWINAPP.CPP文件中加入
    #include <AFXPRIV.H>
    2.创建和修改新的视图类 (View Class)选择菜单的“New Class”创建新的视图类,并将构造函数和析构函数的访问类型由protected改成public,这样用于动态创建视图。完成后保存文件。
    3.创建和绑定新视图(View)
    为了创建和绑定新视图,我们需要修改应用程序类的InitInstance函数,在ProcessShellCommand后面添加如下代码并保存:
    ...
    CView* pActiveView = ((CFrameWnd*) m_pMainWnd)->GetActiveView();
    m_pOldView = pActiveView;
    m_pNewView = (CView*) new CNewView;

    CDocument* pCurrentDoc = ((CFrameWnd*)m_pMainWnd)->GetActiveDocument();

    // Initialize a CCreateContext to point to the active document.
    // With this context, the new view is added to the document
    // when the view is created in CView::OnCreate().
    CCreateContext newContext;
    newContext.m_pNewViewClass = NULL;
    newContext.m_pNewDocTemplate = NULL;
    newContext.m_pLastView = NULL;
    newContext.m_pCurrentFrame = NULL;
    newContext.m_pCurrentDoc = pCurrentDoc;

    // The ID of the initial active view is AFX_IDW_PANE_FIRST.
    // Incrementing this value by one for additional views works
    // in the standard document/view case but the technique cannot
    // be extended for the CSplitterWnd case.
    UINT viewID = AFX_IDW_PANE_FIRST + 1;
    CRect rect(0, 0, 0, 0); // Gets resized later.

    // Create the new view. In this example, the view persists for
    // the life of the application. The application automatically
    // deletes the view when the application is closed.
    m_pNewView->Create(NULL, "AnyWindowName", WS_CHILD, rect, m_pMainWnd, viewID, &newContext);

    // When a document template creates a view, the WM_INITIALUPDATE
    // message is sent automatically. However, this code must
    // explicitly send the message, as follows.
    m_pNewView->SendMessage(WM_INITIALUPDATE, 0, 0);
    ...
    4.实现切换功能函数(Switching Function)
    MYWINAPP.CPP文件中添加如下代码,并保存。
    CView* CMyWinApp::SwitchView( )
    {
       CView* pActiveView =  ((CFrameWnd*) m_pMainWnd)->GetActiveView();

       CView* pNewView= NULL;
       if(pActiveView == m_pOldView)
          pNewView= m_pNewView;
       else
          pNewView= m_pOldView;

       // Exchange view window IDs so RecalcLayout() works.
       #ifndef _WIN32
       UINT temp = ::GetWindowWord(pActiveView->m_hWnd, GWW_ID);
       ::SetWindowWord(pActiveView->m_hWnd, GWW_ID, ::GetWindowWord(pNewView->m_hWnd, GWW_ID));
       ::SetWindowWord(pNewView->m_hWnd, GWW_ID, temp);
       #else
       UINT temp = ::GetWindowLong(pActiveView->m_hWnd, GWL_ID);
       ::SetWindowLong(pActiveView->m_hWnd, GWL_ID, ::GetWindowLong(pNewView->m_hWnd, GWL_ID));
       ::SetWindowLong(pNewView->m_hWnd, GWL_ID, temp);
       #endif
       pActiveView->ShowWindow(SW_HIDE);
       pNewView->ShowWindow(SW_SHOW);
       ((CFrameWnd*) m_pMainWnd)->SetActiveView(pNewView);
       ((CFrameWnd*) m_pMainWnd)->RecalcLayout();
       pNewView->Invalidate();
       return pActiveView;
    }
    5.调用SwitchView函数的实现
    调用SwitchView函数可以通过增加菜单项来是实现。
    void CMainFrame::OnForm1()
    {
    SwitchView();
    }