EternalWindows
WebBrowser コントロール / サイドバーの実装

今回は、サイドバーの実装について説明します。 サイドバーは、ブラウザのこの部分に相当します。

サイドバーの正体は、sidebarという独自のウインドウクラスで作成されたウインドウです。 このウインドウは子ウインドウとしてタブを持っており、 タブが選択された場合はその名前に関連するウインドウを表示することになっています。 お気に入り、フィード、履歴という各ウインドウもサイドバーの子ウインドウですが、 これらはタブが選択された場合に初期化するようにしています。 最初から全てのウインドウを初期化すると、アプリケーションの起動が遅くなることが考えられるからです。

サイトバーはCSidebarで識別され、CWebBrowserContainerによって使用されます。 CWebBrowserContainerはサイドバーを作成したくなった段階で、CSidebar::Createを呼び出します。

BOOL CSidebar::Create(HWND hwndParent)
{
	TCITEM item;
	
	m_hwndSidebar = CreateWindowEx(0, g_szSidebarClassName, NULL, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndParent, (HMENU)ID_SIDEBAR, NULL, NULL);	
	SetWindowLongPtr(m_hwndSidebar, GWLP_USERDATA, (LONG_PTR)this);
	
	m_hwndTab = CreateWindowEx(0, WC_TABCONTROL, TEXT(""), WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, m_hwndSidebar, (HMENU)ID_SIDEBAR_TAB, NULL, NULL);

	item.mask    = TCIF_TEXT;
	item.pszText = TEXT("お気に入り");
	TabCtrl_InsertItem(m_hwndTab, 0, &item);
	
	item.mask    = TCIF_TEXT;
	item.pszText = TEXT("フィード");
	TabCtrl_InsertItem(m_hwndTab, 1, &item);
	
	item.mask    = TCIF_TEXT;
	item.pszText = TEXT("履歴");
	TabCtrl_InsertItem(m_hwndTab, 2, &item);

	m_pFavoriteTree = new CFavoriteTree;
	m_pFeedTree = new CFeedTree;
	m_pHistoryTree = new CHistoryTree;
	
	ChangeTab(0);

	return TRUE;
}

サイドバーのウインドウを作成し、CSidebarのアドレスをウインドウに関連付けます。 このようにすることで、静的なWindowProcからクラスのWindowProcを呼び出すことができます。 タブコントロールを作成するには、ウインドウクラスにWC_TABCONTROLを指定します。 このときに指定する親ウインドウのハンドルは、先に作成したサイドバーのウインドウハンドルになります。 タブコントロールを作成したら、各ウインドウ用のタブに追加します。 各ウインドウというのは、お気に入り、フィード、履歴のことであり、 これらはそれぞれ、CFavoriteTree、CFeedTree、CHistoryTreeで識別されます。 ChangeTabは第1引数のタブを選択するメソッドです。 ここで0以外を指定する場合は、TabCtrl_SetCurSelも呼び出してください。

void CSidebar::ChangeTab(int nSel)
{
	RECT rc;

	if (nSel == 0) {
		if (!m_bCreateFavorite) {
			m_pFavoriteTree->Create(m_hwndSidebar);
			m_bCreateFavorite = TRUE;
		}
		ShowWindow(m_pFavoriteTree->GetWindow(), SW_SHOW);
		ShowWindow(m_pFeedTree->GetWindow(), SW_HIDE);
		ShowWindow(m_pHistoryTree->GetWindow(), SW_HIDE);
	}
	else if (nSel == 1) {
		if (!m_bCreateFeed) {
			m_pFeedTree->Create(m_hwndSidebar);
			m_bCreateFeed = TRUE;
		}
		ShowWindow(m_pFeedTree->GetWindow(), SW_SHOW);
		ShowWindow(m_pFavoriteTree->GetWindow(), SW_HIDE);
		ShowWindow(m_pHistoryTree->GetWindow(), SW_HIDE);
	}
	else if (nSel == 2) {
		if (!m_bCreateHistory) {
			m_pHistoryTree->Create(m_hwndSidebar);
			m_bCreateHistory = TRUE;
		}
		ShowWindow(m_pHistoryTree->GetWindow(), SW_SHOW);
		ShowWindow(m_pFavoriteTree->GetWindow(), SW_HIDE);
		ShowWindow(m_pFeedTree->GetWindow(), SW_HIDE);
	}
	else
		;

	GetClientRect(m_hwndSidebar, &rc);
	ResizeWindow(rc.right - rc.left, rc.bottom - rc.top);
}

タブが選択された場合は、その名前に関連するウインドウを表示しなければなりませんが、 ウインドウがまだ作成されていない場合はこの場で作成するようにしています。 そして、作成が終了したら作成済みを表すフラグをTRUEにします。 nSelが0であるということはお気に入りのウインドウを表示するということであり、 この場合はm_pFavoriteTree->GetWindow()が返すウインドウを表示します。 これに伴って、既に表示されていたウインドウは非表示にするべきですから、 フィードと履歴のウインドウは非表示にしています。 他のタブが選択された場合についても、これと同じ要領になります。 ResizeWindowは、各ウインドウのサイズ調整を行うメソッドです。

サイドバーのウインドウは子ウインドウとして、3つのウインドウとタブを作成しているため、 それらに関する通知をWM_NOTIFYとして受け取ることになります。

case WM_NOTIFY:
	if (((LPNMHDR)lParam)->code == TCN_SELCHANGE) {
		int nSel = TabCtrl_GetCurSel(m_hwndTab);
		ChangeTab(nSel);
	}
	else {
		m_pFeedTree->OnNotify(wParam, lParam);
		m_pHistoryTree->OnNotify(wParam, lParam);
	}
	return 0;

TCN_SELCHANGEはタブが選択されたことを意味し、この場合はChangeTabを呼び出してウインドウの表示を切り替えます。 タブコントロール以外の通知に関しては、パラメータを各ウインドウのクラスへ渡すようにします。 m_pFavoriteTreeはCOMのイベントを通じて通知を受け取るため、OnNotifyというメソッドはありません。


戻る