MFCのFormViewの切り替え

MFCのシングルドキュメントのFormViewを切り替えたい場合があります。例えば、FormView1と2を作っておき、メニューにより切り替える感じです。ここでは、このFormViewの切り替え方法について紹介します。

新しいFromViewをつくる

シングルドキュメントで、基底クラスがCFormViewでプロジェクトを作ります。次に、ソリューションエクスプローラーのプロジェクトを右クリックして、「追加->クラス」から新しいクラスを作ります。この際、MFCクラスにし、基底クラスをCFormViewとします。これで新しいFormViewが追加されます。リソースにもダイアログが追加させるので、そこで編集します。

次に、新しく作られたFormViewのコンストラクタとデストラクタに外部からアクセスできるようにします。初期は「protected:」になっていると思います。これを「public:」に変更します。つまり、

protected:
	クラス名();           // 動的生成で使用される protected コンストラクター
	virtual ~クラス名();

から

public:
	クラス名();           // 動的生成で使用される protected コンストラクター
	virtual ~クラス名();

のようにします。

切り替えメソッドの追加

「プロジェクト名.h」というファイルがあるかと思います。そのファイルの中に、「プロジェクト名App」というクラスがあります。このクラスに

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

とプロパティやメソッドを追加します。m_pOldViewが現在存在するFormViewで、m_pNewViewは新しく作るFormViewです。SwitchViewメソッドでm_pOldViewとm_pNewViewを切り替えます。

m_pOldViewとm_pNewViewからオブジェクトを生成します。そのため、

BOOL プロジェクト名App::InitInstance()

のメソッドにある

	// コマンド ラインで指定されたディスパッチ コマンドです。アプリケーションが
	// /RegServer、/Register、/Unregserver または /Unregister で起動された場合、False を返します。
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;

より下に以下のコードを追加します。

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

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

	CCreateContext newContext;
	newContext.m_pNewViewClass = NULL;
	newContext.m_pNewDocTemplate = NULL;
	newContext.m_pLastView = NULL;
	newContext.m_pCurrentFrame = NULL;
	newContext.m_pCurrentDoc = pCurrentDoc;

	UINT viewID = AFX_IDW_PANE_FIRST + 1;
	CRect rect(0, 0, 0, 0); // Gets resized later.

	m_pNewView->Create(NULL, _T("AnyWindowName"), WS_CHILD, rect, m_pMainWnd, viewID, &newContext);

	m_pNewView->SendMessage(WM_INITIALUPDATE, 0, 0);

m_pOldViewはすでにあるFormViewのオブジェクトを使用します。m_pNewViewについては新しくオブジェクトを生成し、このコードで下準備をしているというわけです。

切り替えメソッドの追加

最後に切り替えメソッドを追加します。以下の命令を「プロジェクト名.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を呼べば、フォームが切り替わります。切り替えイベントに関しては、プロジェクト名Appクラスにイベントを追加させましょう。

参考記事:シングルドキュメントへのマルチビューの追加

著者:安井 真人(やすい まさと)