シングル ドキュメントへのマルチ ビューの追加

Microsoft Foundation Class (MFC) ライブラリを使用して作成されたシングル ドキュメント インターフェイス (SDI) アプリケーションでは、各ドキュメントの種類は単一ビュー型に関連付けられます。 場合によっては、ドキュメントの現在のビューを新しいビューに切り替える機能があることが望ましいことがあります。

ヒント

1 つのドキュメントに複数のビューを実装する他の手順については、CDocument::AddViewCOLLECT の MFC サンプルを参照してください。

この機能を実装するには、新しい CView の派生クラスと、ビューを既存の MFC アプリケーションに動的に切り替えるための追加コードを追加します。

手順は次のとおりです。

このトピックの残りの部分では、次のことを前提としています。

  • CWinApp の派生オブジェクトの名前が CMyWinApp であり、CMyWinAppMYWINAPP.H および MYWINAPP.CPP で宣言および定義されている。

  • 新しい CView の派生オブジェクトの名前が CNewView であり、CNewViewNEWVIEW.H および NEWVIEW.CPP で宣言および定義されている。

既存のアプリケーション クラスを変更する

アプリケーションでビューを切り替えるには、ビューを格納するメンバー変数とビューを切り替えるメソッドを追加して、アプリケーション クラスを変更する必要があります。

MYWINAPP.HCMyWinApp の宣言に次のコードを追加します。

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

新しいメンバー変数 m_pOldView および m_pNewView は、現在のビューと新しく作成されたビューを指します。 新しいメソッド (SwitchView) は、ユーザーの要求に応じてビューを切り替えます。 メソッドの本体については、このトピックの後半の「切り替え関数を実装する」で説明します。

アプリケーション クラスに対する最後の変更では、切り替え関数で使用される Windows メッセージ (WM_INITIALUPDATE) を定義する新しいヘッダー ファイルを含める必要があります。

MYWINAPP.CPP の include セクションに次の行を挿入します。

#include <AFXPRIV.H>

変更を保存し、次の手順に進みます。

新しいビュー クラスを作成して変更する

クラス ビューから利用できる [新しいクラス] コマンドを使用すると、新しいビュー クラスを簡単に作成できます。 このクラスの唯一の要件は、CView から派生することです。 この新しいクラスをアプリケーションに追加します。 新しいクラスをプロジェクトに追加する方法の詳細については、「クラスを追加する」を参照してください。

クラスをプロジェクトに追加したら、一部のビュー クラス メンバーのアクセシビリティを変更する必要があります。

コンストラクターとデストラクターのアクセス指定子を protected から public に変更して、NEWVIEW.H を変更します。 これにより、クラスを動的に作成および破棄し、ビューの外観を表示される前に変更できます。

変更を保存し、次の手順に進みます。

新しいビューを作成してアタッチする

新しいビューを作成してアタッチするには、アプリケーション クラスの InitInstance 関数を変更する必要があります。 この変更では、新しいビュー オブジェクトを作成し、m_pOldViewm_pNewView の両方を 2 つの既存のビュー オブジェクトで初期化する新しいコードを追加します。

新しいビューは 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 メソッドを呼び出すコードを追加します。 これは、いくつかの方法で実現できます。ユーザーが選択できる新しいメニュー項目を追加する方法と、特定の条件が満たされたときにビューを内部で切り替える方法があります。

新しいメニュー項目とコマンド ハンドラー関数を追加する方法の詳細については、「コマンドとコントロール通知のハンドラー」を参照してください。

関連項目

ドキュメントおよびビュー アーキテクチャ