第39回 ステータスバー関連処理の再実装する (タブブラウザーを作る)

tabbrowser160.gif
前回はステータスバー関連処理を見直す前段階として「MainFrm.h」内の処理をコメントアウトした。今回はコメントアウトした処理を参考にしながらステータスバー関連処理を新しく作り直す。

まず「MainFrm.h」からCIconManagerを移動してくる。そしてスタータスバー用のクラスCIELikeStatusbarを作る。処理内容はCMainFrameから移動してきたものに少し変更を加えた程度だ。
#include "atlcoll.h"

//■CMainFrameから移動
//アイコンを管理
//アイコンをAddする関数などは未実装。今後追加
class	CIconManager
{
protected:
	CAtlArray<HICON>	_ahIcon;		//アイコンリスト

public:
	CIconManager()
	{
		SetFixedIndexIcon();		//固定インデックスのアイコンを追加
	}

	~CIconManager()
	{
		Destroy();
	}

	enum	ICON_INDEX
	{
		ICON_WARNING_SM = 0,			//警告アイコン。スクリプトエラー時に利用
	};

	HICON	GetIcon(UINT nIconIndex)
	{
		if(nIconIndex >= _ahIcon.GetCount())
			return	NULL;

		return	_ahIcon[nIconIndex];
	}

protected:

	//固定インデックスのアイコンを追加
	//かならずICON_INDEXと同じ値になるようにする
	bool	SetFixedIndexIcon(void)
	{
		ATLASSERT(_ahIcon.GetCount() == 0);		//すでに設定されてる?
		if(_ahIcon.GetCount())
			return	false;

		size_t	nIndex;
		HICON	hIcon;

		//警告アイコン
		//LoadImageで32x32を読み込み、CopyImageで16x16に縮小。LoadImageのHICONはLR_SHAREDなのでDestroyIcon必要なし
		hIcon = (HICON)::LoadImage(NULL,MAKEINTRESOURCE(OIC_WARNING),IMAGE_ICON,0,0,LR_DEFAULTSIZE | LR_SHARED);
		hIcon = (HICON)::CopyImage(hIcon,IMAGE_ICON,::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON),LR_COPYFROMRESOURCE);
		nIndex = _ahIcon.Add(hIcon);
		ATLASSERT(nIndex == ICON_WARNING_SM);

		return	true;
	}

	//保持してるアイコンの破棄
	void	Destroy(void)
	{
		size_t	i;
		size_t	nSize;

		nSize = _ahIcon.GetCount();
		for(i = 0; i < nSize; i++)
		{
			if(_ahIcon[i] == NULL)
				continue;
			::DestroyIcon(_ahIcon[i]);
		}
		_ahIcon.RemoveAll();
	}
};




//■追加
class	CIELikeStatusbar	: public CWindowImpl<CIELikeStatusbar>
{

	//■CMainFrameから移動
	CIconManager	_cIconList;

	//■CMainFrameから移動
	CProgressBarCtrl	_wndProgressBar;			//ステータスバーに配置するプログレスバーコントロール


	CAtlString	_strText;

	//■CTabBrowser100Viewから移動
	long	_nLastProgress;			//最後に受け取ったプログレス情報
	long	_nLastProgressMax;		//最後に受け取ったプログレス最大値

	//■CTabBrowser100Viewから移動
	bool	_bPageError;	//現在のページでスクリプトエラーなどがあればtrue、通常はfalse

public:

	CIELikeStatusbar()
	{
		_nLastProgress		= -1;
		_nLastProgressMax	= -1;
		_bPageError = false;
	}


	BEGIN_MSG_MAP(CIELikeStatusbar)
		MESSAGE_HANDLER(WM_SIZE, OnSize)		//■CMainFrameから移動
	END_MSG_MAP()


	//■CMainFrameから移動
	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		bHandled = FALSE;

		if(_wndProgressBar.IsWindow())
			RefreshProgressBar();		//プログレスバー表示更新

		return	0;
	}


	//■CMainFrameから移動。m_hWndStatusBarをm_hWndに変更
	//bVisible=falseならプログレスバーを消す
	//nProgress < 0、nProgressMax < 0ならプログレス設定はしない
	//nProgressMax < nProgressなら強制的に非表示にする
	bool	RefreshProgressBar(int nProgress=-1,int nProgressMax=-1,bool bVisible=true)
	{
		//■追加
		if((nProgress >= 0 && nProgressMax  >= 0) || (nProgressMax < nProgress))
		{
			//状態を保存しておく
			_nLastProgress		= nProgress;
			_nLastProgressMax	= nProgressMax;
		}

		if(::IsWindow(m_hWnd) == FALSE)
			return	false;				//ステータスバー表示してない

		int		nProgressWidth = 100;			//■プログレスバーの幅は100px固定とする
		CRect	rect;
		CStatusBarCtrl	wndStatusBar = m_hWnd;

		if(_nLastProgressMax < _nLastProgress)		//■変更
			bVisible = false;

		if(bVisible == false)
			nProgressWidth = 0;

		//ステータスバーのペインの作成/更新
		{
			int		pnParts[2];						//2つペインを作成(1つはデフォルト、もう1つはプログレスバー用)

			wndStatusBar.GetClientRect(&rect);
			pnParts[0] = rect.Width() - nProgressWidth;
			pnParts[1] = rect.Width();

			wndStatusBar.SetParts(sizeof(pnParts) / sizeof(pnParts[0]),pnParts);
		}


		//プログレスバーの生成/更新
		{
			wndStatusBar.GetRect(1,&rect);			//2つめのペインをプログレスバーに利用する

			if(_wndProgressBar.IsWindow() == FALSE)
				_wndProgressBar.Create(m_hWnd,rect,0,WS_CHILD);	//プログレスバーを生成
			else
				_wndProgressBar.MoveWindow(&rect);			//位置を移動

			if(bVisible)
			{
				if(_wndProgressBar.IsWindowVisible() == FALSE)
					_wndProgressBar.ShowWindow(SW_NORMAL);		//可視に
			}
			else
			{
				if(_wndProgressBar.IsWindowVisible())
					_wndProgressBar.ShowWindow(SW_HIDE);		//不可視に
			}

			//■変更
			//プログレスの設定
			if(_nLastProgress >= 0)
				_wndProgressBar.SetRange(0,_nLastProgressMax);
			if(_nLastProgress >= 0)
				_wndProgressBar.SetPos(_nLastProgress);
		}

		return	true;
	}




	//ステータスバー表示更新
	bool	Refresh(bool bCapture)
	{
		if(bCapture == false)
		{
			if(_wndProgressBar.IsWindow())
			{
				if(_wndProgressBar.IsWindowVisible())
					_wndProgressBar.ShowWindow(SW_HIDE);		//不可視に
			}
			return	true;
		}

		if(IsWindow() == FALSE)
			return	false;

		//ステータスバーのテキスト変更
		{
			SetText(_strText);
		}

		//ステータスバーのエラーアイコン変更
		{
			CStatusBarCtrl	wndStatusBar = m_hWnd;

			if(_bPageError)
				wndStatusBar.SetIcon(0,_cIconList.GetIcon(CIconManager::ICON_WARNING_SM));
			else
				wndStatusBar.SetIcon(0,NULL);
		}

		//プログレス変更
		{
			RefreshProgressBar(_nLastProgress,_nLastProgressMax);
		}

		return	true;
	}


	bool	SetText(LPCTSTR pszText)
	{
		_strText = pszText;

		if(IsWindow() == FALSE)
			return	true;

		SetWindowText(pszText);

		return	true;
	}

	bool	SetPageError(bool bError)
	{
		_bPageError = bError;			//エラーが発生したことを保持

		if(IsWindow())
		{
			CStatusBarCtrl	wndStatusBar = m_hWnd;

			if(_bPageError)
				wndStatusBar.SetIcon(0,_cIconList.GetIcon(CIconManager::ICON_WARNING_SM));
			else
				wndStatusBar.SetIcon(0,NULL);
		}

		return	true;
	}
};

tabbrowser162.gif そしてビュークラス内のステータスバー関連処理をCIELikeStatusbarを利用するものに変更しいらない部分を削除する。
	//■処理内容変更
	//ステータスバーのメッセージ変更
	void	ChangeStatusText(LPCTSTR pszText)
	{
		_strLastStatusText = pszText;		//いつでも参照できるようにクラスのメンバーに保存しておく

		GetLastStatusText(_strLastStatusText);

		_wndStatusbar.SetText(_strLastStatusText);
	}

	void __stdcall OnStatusTextChange(BSTR bstrText)
	{
		ChangeStatusText((CAtlString)bstrText);
	}


	//■処理内容変更
	//エラー発生/解消時に呼ぶ
	//bError=trueならエラー発生
	void	SetErrorState(bool bError)
	{
		_bPageError = bError;

		if(bError)
			ChangeStatusText(NULL);

		_wndStatusbar.SetPageError(bError);
	}

	//■削除
	//bool	IsPageError(void)
	//{
	//	return	_bPageError;
	//}

	LRESULT OnDnpScriptError(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		SetErrorState(true);
		return	0;
	}

	//最後にIEコントロールから受け取ったステータスバー用メッセージを返す
	void	GetLastStatusText(CAtlString& strText)
	{
		strText = _strLastStatusText;

		//表示する文字がないときで、現在ページにエラーがあればエラーメッセージを返す
		if(_bPageError && strText == _T(""))
			strText = _T("ページでエラーが発生しました。");
	}

	void __stdcall OnDownloadComplete()
	{
	}

	void __stdcall OnCommandStateChange(long lCommand,VARIANT_BOOL vbEnable)
	{
	}

	void __stdcall OnDownloadBegin(void)
	{
		SetErrorState(false);		//エラー情報をリセット
	}


	//■削除
	//long	_nLastProgress;			//最後に受け取ったプログレス情報
	//long	_nLastProgressMax;		//最後に受け取ったプログレス最大値



	//■処理内容変更
	void __stdcall OnProgressChange(long lProgress,long lProgressMax)
	{
		if(lProgress < 0 || (lProgressMax == 0 && lProgress == 0))	//MSDNには記述がないが(0,0)で終わることが多いため(0,0)でも非表示
			lProgressMax = lProgress - 1;		//lProgressMax < lProgress にしておく -> 自動的にプログレスバーが消える

		_wndStatusbar.RefreshProgressBar(lProgress,lProgressMax);
	}


	//■削除
	////最後にIEコントロールから受け取ったプログレス情報を返す
	//void	GetLastProgress(long& nProgress,long& nProgressMax)
	//{
	//	nProgress		= _nLastProgress;
	//	nProgressMax	= _nLastProgressMax;
	//}

tabbrowser161.gif コンストラクタの不要部分も忘れずにコメントアウトしておく。
	CTabBrowser100View(CTabView* pTabView,HWND hWndRebarIE)
	{
		_pTabView = pTabView;
//		_nLastProgress		= 0;		//■削除
//		_nLastProgressMax	= -1;		//■削除
		_hWndRebarIE = hWndRebarIE;
		_bPageError = false;
	}

tabbrowser163.gif 今回の修正ではビュークラス側から直接ステータスバーに文字表示などを行っている。そのままだと複数のタブ(ビュー)が開いているときに、複数のビューからステータスバーにアクセスしてしまうことになるので、タブ(ビュー)がアクティブなときだけステータスバーへのアクセスが有効になるようにする。
	CIELikeStatusbar	_wndStatusbar;		//■追加


	//■追加
	//メインウインドウから呼ばれる
	//bCapture=trueでこのビューがステータスバーを制御する
	//bCapture=falseでこのビューがステータスバーを解放する
	bool	SetStatusBar(HWND hWnd,bool bCapture)
	{
		if(bCapture)
		{
			if(_wndStatusbar.IsWindow())
				return	false;
			_wndStatusbar.SubclassWindow(hWnd);
			_wndStatusbar.Refresh(true);
		}
		else
		{
			if(_wndStatusbar.IsWindow())
				_wndStatusbar.UnsubclassWindow();
			_wndStatusbar.Refresh(false);
		}

		return	true;
	}

tabbrowser164.gif 「MainFrm.h」内でアクティブなビューにだけステータスバーを渡す。
	//タブが選択されたときの処理
	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);	//ステータスバー解放
				}
			}

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


		bool		ret;
		CTabBrowser100View*	pView;

		pView = GetActivePageView();		//アクティブビュー取得
		if(pView == NULL)
			return	0;

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

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

		return	0;
	}

tabbrowser165.gif
これでビルド/実行すると再びステータスバーへの表示が行われるようになった。

しかしまだステータスバーのダブルクリックに関する処理を再実装していない。次回はそれを行う。

プロジェクトファイルをダウンロード


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