向单个文档添加多个视图

在使用 Microsoft 基础类 (MFC) 库创建的单文档界面 (SDI) 应用程序中,每个文档类型都与单个视图类型相关联。 在某些情况下,希望能够使用新视图切换文档的当前视图。

提示

有关为单个文档实现多个视图的其他过程,请参阅 CDocument::AddViewCOLLECT MFC 示例。

可以通过添加新的 CView 派生类和用于将视图动态切换到现有 MFC 应用程序的其他代码来实现此功能。

步骤如下:

本主题的其余部分假定存在以下情况:

  • CWinApp-derived 对象的名称是 CMyWinAppCMyWinApp 是在 MYWINAPP.H 和 MYWINAPP.CPP 中声明和定义的

  • CNewView 是新的 CView-derived 对象的名称,CNewView 是在 NEWVIEW.H 和 NEWVIEW.CPP 中声明和定义的

修改现有应用程序类

若要使应用程序在视图之间切换,需要通过添加用于存储视图的成员变量和用于切换视图的方法来修改应用程序类。

将以下代码添加到 MYWINAPP.H 中的声明 CMyWinApp

CView *m_pOldView;
CView *m_pNewView;
CView *SwitchView();

新成员变量(m_pOldViewm_pNewView)指向当前视图和新创建的视图。 新方法 (SwitchView) 在用户请求时切换视图。 本主题稍后将在实现切换功能中讨论该方法的主体。

对应用程序类的最后一次修改需要包括一个新的头文件,该文件定义在切换函数中使用的 Windows 消息 (WM_INITIALUPDATE)

在 MYWINAPP.CPP 的包含部分中插入以下行

#include <AFXPRIV.H>

保存更改并继续下一步。

创建和修改新视图类

通过使用“类视图”中提供的 New Class 命令,可以轻松创建新的视图类。 此类的唯一要求是它派生自 CView。 将此新类添加到应用程序。 有关向项目添加新类的特定信息,请参阅添加类

将类添加到项目后,需要更改某些视图类成员的辅助功能。

通过将构造函数和析构函数的访问说明符从 protected 更改为 public 来修改 NEWVIEW.H。 这允许动态创建和销毁类,并在视图外观可见之前对其进行修改。

保存更改并继续下一步。

创建和附加新视图

若要创建和附加新视图,需要修改应用程序类的 InitInstance 函数。 修改将添加新代码,该代码将创建新的视图对象,然后使用两个现有视图对象初始化 m_pOldViewm_pNewView

由于新视图是在 InitInstance 函数中创建的,因此新视图和现有视图在应用程序的生存期内都会保留。 但是,应用程序可以同样轻松地动态创建新视图。

在调用 ProcessShellCommand 后插入以下代码:

CView *pActiveView = ((CFrameWnd *)m_pMainWnd)->GetActiveView();
m_pOldView = pActiveView;
m_pNewView = (CView *)new CNewView;
if (NULL == m_pNewView)
   return FALSE;

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, _T("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);

保存更改并继续下一步。

实现切换函数

在上一步中,你添加了用于创建和初始化新视图对象的代码。 最后一个主要部分是实现切换方法 SwitchView

在应用程序类 (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;
}

保存更改并继续下一步。

添加对切换视图的支持

最后一步涉及添加代码,使其在应用程序需要于视图之间切换时调用 SwitchView 方法。 这可以通过多种方式完成:通过添加新的菜单项供用户选择,或者在满足某些条件时在内部切换视图。

有关添加新菜单项和命令处理程序函数的详细信息,请参阅命令和控制通知的处理程序

另请参阅

文档/视图体系结构