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

前回はインストールされて利用可能なInternet Explorer用ツールバーがすべて表示されるようにした。
今回は右クリックメニューから選んで表示/非表示できるようにする。
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;
}

今までツールバーの管理をCAtlArray<CDummyWnd*>にしていたが、このままだと表示/非表示の切り替えがややこしいので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;
}
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;
}
};
デストラクタ内の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;
}
}
_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;
}
_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;
}
これまで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;
}
最後にビューウインドウ側で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;
}
![]()
これでビルド/実行すると、ツールバー部分の右クリックメニューによりInternet Explorer用ツールバーを選んで表示/非表示できるようになった。
次回はお気に入りメニューをきちんとしたものに作り直す準備をする。
