次の方法で共有


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

MFC (Microsoft Foundation Class) ライブラリを使用して作成されたシングル ドキュメント インターフェイス (SDI: Single-Document Interface) アプリケーションでは、各ドキュメント タイプは 1 つのビュー タイプに関連付けられています。 このため、ドキュメントの現在のビューを新しいビューに切り替える機能が必要な場合もあります。

ヒント

シングル ドキュメントにマルチ ビューを実装する手順の詳細については、「CDocument::AddView」と、MFC サンプルの COLLECT を参照してください。

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

その手順は次のとおりです。

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

  • ビュー クラスの新規作成と変更

  • ビューの新規作成と結び付け

  • 切り替え関数の実装

  • ビュー切り替えサポートの追加

このトピックは、これ以降、次のことを前提にして説明します。

  • CWinApp 派生オブジェクトの名前は CMyWinApp であり、CMyWinApp は MYWINAPP.H と MYWINAPP.CPP で宣言し、定義されています。

  • 新しい CView 派生オブジェクトの名前は CNewView であり、CNewView は NEWVIEW.H と NEWVIEW.CPP で宣言し、定義されています。

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

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

MYWINAPP.H で、CMyWinApp の宣言に次のコードを追加します。

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

新しいメンバー変数の m_pOldView と m_pNewView はそれぞれ、現在のビューと新規作成されたビューを示すポインターです。 新しいメソッド (SwitchView) は、ユーザーからの要求に応じてビューを切り替えます。 メソッドの本体の詳細については、このトピックで後述する「切り替え関数の実装」を参照してください。

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

MYWINAPP.CPP の include セクションに次の行を挿入してください。

#include <AFXPRIV.H>

変更内容を保存して次のステップに進みます。

ビュー クラスの新規作成と変更

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

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

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

変更内容を保存して次のステップに進みます。

ビューの新規作成と結び付け

新しいビューを作成し、結び付けるには、アプリケーション クラスの InitInstance 関数を変更する必要があります。 この変更では、新しいビュー オブジェクトを作成して m_pOldView と m_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 メソッドを呼び出すコードの追加が必要です。 これは、いくつかの方法で行うことができます。新しいメニュー項目を選択するユーザーを追加するか、ビューの内部が切り替え特定の条件が満たされています。

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

参照

概念

ドキュメント/ビュー アーキテクチャ