第56回 右クリックメニューでIEツールバーを選択する (タブブラウザーを作る)

tabbrowser250.gif
前回はインストールされて利用可能なInternet Explorer用ツールバーがすべて表示されるようにした。
今回は右クリックメニューから選んで表示/非表示できるようにする。

ツールバーなどのエリアでの右クリック処理はWM_PARENTNOTIFYとして届く。これを受け取ったらRB_HITTESTを利用して右クリックされた場所がツールバーならIEツールバー選択用のメニューを表示する。 そして選択されたIEツールバーの表示/非表示を切り替える。
		NOTIFY_CODE_HANDLER(TBVN_CONTEXTMENU, OnTabContextMenu)
		NOTIFY_CODE_HANDLER(TBVN_PAGEACTIVATED, OnTabPageActivated)
		MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
		MESSAGE_HANDLER(WM_PARENTNOTIFY, OnParentNotify)			//■追加
		COMMAND_RANGE_HANDLER(ID_FAVORITE_FIRST,ID_FAVORITE_LAST,OnFavorite)
		CHAIN_MSG_MAP_MEMBER(_cFovMenu)
		CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
		CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
	END_MSG_MAP()


	//■追加
	LRESULT OnParentNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		if(wParam != WM_RBUTTONDOWN)
			return	0;

		size_t	nIndex;
		POINT	pt;

		::GetCursorPos(&pt);

		{
			RBHITTESTINFO	info;

			::ZeroMemory(&info,sizeof(RBHITTESTINFO));
			info.pt = pt;
			ScreenToClient(&info.pt);
			if(::SendMessage(m_hWndToolBar,RB_HITTEST,NULL,(LPARAM)&info) < 0)
				return	0;
		}

		//メニュー表示
		{
			HMENU	hMenu;
			size_t	i;
			size_t	nSize;

			nSize = _acAvailableIEToolbar.GetCount();
			if(nSize == 0)			//利用可能なIEツールバーがない
				return	0;

			hMenu = ::CreatePopupMenu();

			for(i = 0; i < nSize; i++)
			{
				::InsertMenu(hMenu,i,MF_BYPOSITION | MF_STRING,i + 1,_acAvailableIEToolbar[i].strName);

				if(_acAvailableIEToolbar[i].IsVisible())
					::CheckMenuItem(hMenu,i + 1,MF_CHECKED | MF_BYCOMMAND);
			}

			nIndex = (size_t)::TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_RETURNCMD,pt.x,pt.y,NULL,m_hWnd,NULL);
			::DestroyMenu(hMenu);

			if(nIndex == 0)
				return	0;			//選択されなかった
			nIndex--;
		}


		if(_acAvailableIEToolbar[nIndex].IsVisible() == false)
		{
			//ツールバーの表示
			AddIEToolbar(nIndex);
		}
		else
		{
			//ツールバーの消去
			int		i;
			int		nSize;
			CTabBrowser100View*	pView;

			nSize = m_view.GetPageCount();
			for(i = 0; i < nSize; i++)
			{
				pView = GetPageView(i);
				if(pView == NULL)
					continue;

				pView->RemoveIEToolbar(_acAvailableIEToolbar[nIndex].pwndDummy->m_hWnd);
			}

			::SendMessage(m_hWndToolBar,RB_DELETEBAND,(WPARAM)_acAvailableIEToolbar[nIndex].pwndDummy->GetRebarIndex(),NULL);

			_acAvailableIEToolbar[nIndex].pwndDummy->DestroyWindow();
			delete	_acAvailableIEToolbar[nIndex].pwndDummy;
			_acAvailableIEToolbar[nIndex].pwndDummy = NULL;
		}


		bHandled = FALSE;
		return	0;
	}

tabbrowser253.gif
今までツールバーの管理をCAtlArray<CDummyWnd*>にしていたが、このままだと表示/非表示の切り替えがややこしいのでacAvailableIEToolbarに移動する。

また、AddIEToolbarの引数もクラスIDから_acAvailableIEToolbarへのインデックスに変更しておく。
//	CAtlArray<CDummyWnd*>	_apwndDummy;	//■削除_acAvailableIEToolbarの中へ

	//■変更。引数からCLSIDから_acAvailableIEToolbarへのインデックスに変更。
	bool	AddIEToolbar(size_t nIndex)
	{
		IID			clsidIDeskBand;
		CDummyWnd*	pwndDummy;

		if(nIndex >= _acAvailableIEToolbar.GetCount())
			return	false;			//不正なインデックス
		if(_acAvailableIEToolbar[nIndex].IsVisible())
			return	false;			//すでに表示されている

		clsidIDeskBand = _acAvailableIEToolbar[nIndex].clsidToolbar;

		pwndDummy = new CDummyWnd(clsidIDeskBand);

		//ダミーウインドウを生成し、リバーに割り当てる。これはIEツールバーに利用
		pwndDummy->Create(m_hWnd,CRect(0,0,500,24),0,WS_CHILD);
		AddSimpleReBarBand(*pwndDummy,0,TRUE);						//1行表示

		//IEツールバー用のrebarのインデックス取得。_wndDummyへ割り当てると同時にrebarを非表示に
		{
			UINT	nCount;

			nCount = (UINT)::SendMessage(m_hWndToolBar,RB_GETBANDCOUNT,NULL,NULL);
			pwndDummy->_nBandID = nCount + ATL_IDW_BAND_FIRST - 1;

			if(m_view.IsWindow() && m_view.GetPageCount())
			{
				//IEツールバーの生成
				//タブの数だけ一気に生成しているから効率が悪すぎる。
				//アクティブになったときに生成すべき
				{
					size_t	i;
					size_t	nSize;
					CTabBrowser100View*	pView;

					nSize = m_view.GetPageCount();
					for(i = 0; i < nSize; i++)
					{
						pView = GetPageView(i);
						if(pView == NULL)
							continue;

						if(i == m_view.GetActivePage())
							pView->AddIEToolbar(*pwndDummy,true);		// IEツールバー生成
						else
							pView->AddIEToolbar(*pwndDummy,false);		// IEツールバー生成
					}
				}
				pwndDummy->ShowRebar(true);			//表示する
			}
			else
				pwndDummy->ShowRebar(false);		//非表示にする
		}

		_acAvailableIEToolbar[nIndex].pwndDummy = pwndDummy;

		return	true;
	}

tabbrowser254.gif IDeskBandの親ウインドウとして利用するpwndDummyとIsVisibleを用意した。ただしIsVisibleは実際にIDeskBandが表示状態かどうかまではチェックしていない。
	//■変更 pwndDummyを追加
	class	CAvailableIEToolbar
	{
	public:
		CAtlString	strName;
		IID			clsidToolbar;
		CDummyWnd*	pwndDummy;

		CAvailableIEToolbar()
		{
			pwndDummy = NULL;
			clsidToolbar = GUID_NULL;
		}

		CAvailableIEToolbar(const IID& clsid,LPCTSTR pszName)
		{
			pwndDummy = NULL;
			clsidToolbar = clsid;
			strName = pszName;
		}

		bool	IsVisible(void)
		{
			if(pwndDummy == NULL || pwndDummy->IsWindow() == FALSE)
				return	false;
			return	true;
		}
	};

tabbrowser249.gif デストラクタ内のCDummyWndのdelete処理も_acAvailableIEToolbarに変更する。
	//■変更
	~CMainFrame()
	{
		size_t	i;
		size_t	nSize;

		nSize = _acAvailableIEToolbar.GetCount();
		for(i = 0; i < nSize; i++)
		{
			if(_acAvailableIEToolbar[i].pwndDummy == NULL)
				continue;
			delete	_acAvailableIEToolbar[i].pwndDummy;
			_acAvailableIEToolbar[i].pwndDummy = NULL;
		}
	}

tabbrowser251.gif _acAvailableIEToolbarのCDummyWndを取得するように変更する。
	//■変更
	//タブが選択されたときの処理
	LRESULT OnTabPageActivated(int idCtrl, LPNMHDR pnmh, BOOL& bHandled)
	{
		if(pnmh == NULL)
			return	0;

		//全てのビューに対してタブ変更があったことを通知
		{
			int		i;
			int		nCount;
			CTabBrowser100View*	pView;

			nCount = m_view.GetPageCount();
			for(i = 0; i < nCount; i++)
			{
				pView = GetPageView(i);
				if(pView == NULL)
					continue;

				if(pnmh->idFrom == i)
					pView->OnTabPageChange(true);
				else
				{
					pView->OnTabPageChange(false);
					pView->SetStatusBar(m_hWndStatusBar,false);	//ステータスバー解放
				}
			}

			pView = GetActivePageView();
			if(pView)
				pView->SetStatusBar(m_hWndStatusBar,true);		//ステータスバーセット
		}


		bool		ret;
		CTabBrowser100View*	pView;
		size_t		i;
		size_t		nSize;
		bool		bVisible;
		nSize = _acAvailableIEToolbar.GetCount();

		pView = GetActivePageView();		//アクティブビュー取得
		if(pView == NULL)
			bVisible = false;
		else
			bVisible = true;

		for(i = 0; i < nSize; i++)
		{
			if(_acAvailableIEToolbar[i].pwndDummy)
				_acAvailableIEToolbar[i].pwndDummy->ShowRebar(bVisible);				//リバー表示
		}

		if(pView == NULL)
			return	0;

		//アドレスバーのURL変更
		{
			CAtlString	strURL;

			ret = pView->GetURL(strURL);		//URL取得
			if(ret)
				_wndAddressBar.SetWindowText(strURL);
		}

		return	0;
	}

tabbrowser252.gif _acAvailableIEToolbarのCDummyWndを取得するように変更する。
	//■変更
	//タブの新規作成
	//nPosはタブを追加する場所。nPos<0(もしくはnPos=m_view.GetPageCount())で一番後ろ、
	//そのほかの数値はCTabView::InsertPageにそのまま渡す
	//
	//戻ったポインタは自動削除されるため、deleteの必要なし
	//
	CTabBrowser100View*	CreateNewTab(LPCTSTR pszURL,LPCTSTR pszTitle,int nPos=-1,int nImage=-1)
	{
		bool	ret;
		CTabBrowser100View*	pView;

		pView = new CTabBrowser100View(&m_view);	//タブビューのポインタを渡す
		if(pView == NULL)
			return	NULL;

		//ビューウインドウ生成
		if(pszURL == NULL || *pszURL == NULL)
			pView->Create(m_view, rcDefault, _T("about:blank"), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_HSCROLL | WS_VSCROLL, 0);
		else
			pView->Create(m_view, rcDefault, pszURL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_HSCROLL | WS_VSCROLL, 0);
		if(pView->IsWindow() == FALSE)
		{
			delete	pView;
			return	NULL;		//ビューウインドウ生成失敗
		}

		//タブにビューを割り当てる
		if(nPos < 0)
			nPos = m_view.GetPageCount();
		if(pszTitle)
			ret = m_view.InsertPage(nPos,pView->m_hWnd,pszTitle,nImage,pView);
		else
			ret = m_view.InsertPage(nPos,pView->m_hWnd,_T(""),nImage,pView);

		if(ret == false)
		{
			delete	pView;
			return	NULL;		//タブへの追加失敗
		}

		//IEツールバーの生成
		{
			size_t	i;
			size_t	nSize;

			nSize = _acAvailableIEToolbar.GetCount();
			for(i = 0; i < nSize; i++)
			{
				if(_acAvailableIEToolbar[i].pwndDummy)
					pView->AddIEToolbar(*_acAvailableIEToolbar[i].pwndDummy,true);		//IEツールバー生成
			}
		}

		return	pView;
	}

tabbrowser255.gif これまでOnCreateでは見つかったすべてのIEツールバーを表示していた。これをIEツールバーを探すにとどめる。
	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		// コマンドバー ウィンドウの作成
		HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);
		// メニューのアタッチ
		m_CmdBar.AttachMenu(GetMenu());
		// コマンドバー画像の読み込み
		m_CmdBar.LoadImages(IDR_MAINFRAME);
		// 以前のメニューの削除
		SetMenu(NULL);

		HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);

		CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
		AddSimpleReBarBand(hWndCmdBar);
		AddSimpleReBarBand(hWndToolBar, NULL, TRUE);

		_wndAddressBar.Create(m_hWnd,CRect(0,0,200,200),0,WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_CLIPCHILDREN,WS_EX_CLIENTEDGE);
		AddSimpleReBarBand(_wndAddressBar,0,TRUE);	//アドレスバーを1列で表示


		//■削除
		//{
		//	size_t	i;
		//	size_t	nSize;

		//	EnumAvailableIEToolbar();

		//	nSize = _acAvailableIEToolbar.GetCount();
		//	for(i = 0; i < nSize; i++)
		//	{
		//		AddIEToolbar(_acAvailableIEToolbar[i].clsidToolbar);
		//	}
		//}

		//■追加
		EnumAvailableIEToolbar();			//IEツールバーの列挙

		CreateSimpleStatusBar();

		m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_CLIENTEDGE);

		UIAddToolBar(hWndToolBar);
		UISetCheck(ID_VIEW_TOOLBAR, 1);
		UISetCheck(ID_VIEW_STATUS_BAR, 1);

		// メッセージ フィルターおよび画面更新用のオブジェクト登録
		CMessageLoop* pLoop = _Module.GetMessageLoop();
		ATLASSERT(pLoop != NULL);
		pLoop->AddMessageFilter(this);
		pLoop->AddIdleHandler(this);

		CMenuHandle menuMain = m_CmdBar.GetMenu();
		m_view.SetWindowMenu(menuMain.GetSubMenu(WINDOW_MENU_POSITION));

		_cTabImageList.Create(16,16,ILC_COLOR | ILC_MASK,1,10);
		m_view.SetImageList(_cTabImageList);

		return 0;
	}

tabbrowser256.gif 最後にビューウインドウ側でIEツールバーを非表示にする処理を追加する。 今回は表示/非表示は生成/破棄により実現している。そのためタブが多い場合はかなり負荷がかかってしまう。
	//■追加
	bool	RemoveIEToolbar(HWND hWndIERebar)
	{
		size_t	i;
		size_t	nSize;

		nSize = _aToolbarInfo.GetCount();
		for(i = 0; i < nSize; i++)
		{
			if(_aToolbarInfo[i]._hWndRebarIE != hWndIERebar)
				continue;

			_aToolbarInfo[i]._hWndRebarIE = NULL;

			if(_aToolbarInfo[i]._pIDeskBand == NULL)
				return	true;

			_aToolbarInfo[i]._pIDeskBand->ShowDW(FALSE);
			_aToolbarInfo[i]._pIDeskBand->CloseDW(0);
			_aToolbarInfo[i]._pIDeskBand = NULL;

			return	true;
		}

		return	false;
	}

tabbrowser257.gif
これでビルド/実行すると、ツールバー部分の右クリックメニューによりInternet Explorer用ツールバーを選んで表示/非表示できるようになった。

次回はお気に入りメニューをきちんとしたものに作り直す準備をする。

ファイルをダウンロード


カテゴリー「タブブラウザーを作る」 のエントリー