七达网是国内最新、最齐、最安全的软件下载基地!

关于我们最近更新热门排行

首页 软件 游戏 应用 文章 专题

新闻资讯软件应用软件教程编程开发 操作系统游戏攻略安卓应用安卓游戏
当前位置:首页 ›› 编程开发 ›› 一个显示进度条的WTL状态栏类

一个显示进度条的WTL状态栏类

2014-03-02 13:03   作者:mousebaby808   来源:csdn   浏览:377   评论:3  

引言

好久没用WTL写代码了,WTL已经更新到8.1版本,但依旧没有提供对VS2013的支持,网上有相关更改想到模板的方法,但向导界面和VS2013的风格严重不搭,丑的一逼……好在WTL代码结构很简单,用不用向导都无所谓,不用也罢。

自从C++0x/11发表以来,ATL/WTL的威力逐渐展现出来,ATL/WTL和STL的配搭是那么的自然和顺当,不像MFC,带齐了所有的东西,但总显得和C++的新特性格格不入。

这次需要用一个带进度条状态栏,第7下载以前也用MFC做过一个,这次用WTL重新做一个,要干的活比用MFC多一些,但显然代码的结构要比MFC清晰很多,至少每一步在做什么都很清楚,不像MFC,很多时候的调用都糊里糊涂,不明所以然的。

通过继承WTL的CMultiPaneStatusBarCtrlImpl类(多面板状态栏类),可以做到在状态栏的指定面板中加入进度条(其它类似控件也可以采用完全类似的方法),整个代码如下:

代码

ProgressStatusBar.h

#pragma once

#include <list>
#include <algorithm>

/// <summary>
/// 七达网下载带进度条的状态栏
/// </summary>
class CProgressStatusBar : public CMultiPaneStatusBarCtrlImpl<CProgressStatusBar>
{
public:

	/// <summary>
	/// 定义基类类型
	/// </summary>
	typedef CMultiPaneStatusBarCtrlImpl<CProgressStatusBar> Base;

	/// <summary>
	/// 定义保存进度条组件的结构体
	/// </summary>
	struct CProgressBarCtrlPair
	{
		UINT nPaneId;		// 进度条组件的Id
		CProgressBarCtrl* pProgressBarCtrl;	// 进度条组件的指针
	};

	/// <summary>
	/// 定义保存进度条组件结构体的链表类型
	/// </summary>
	typedef std::list<CProgressBarCtrlPair> CProgressBarCtrlList;

	/// <summary>
	/// 定义当前组件的窗体类名称,并继承已知的窗体类
	/// </summary>
	DECLARE_WND_SUPERCLASS(_T("softparty.controlex.progressstatusbar"), Base::GetWndClassName())

	/// <summary>
	/// 消息映射表
	/// </summary>
	BEGIN_MSG_MAP_EX(CProgressStatusBar)
		MESSAGE_HANDLER(WM_SIZE, OnSize)	// 处理WM_SIZE消息
		CHAIN_MSG_MAP(Base)		// 将其余消息链接到基类
	END_MSG_MAP()

	/// <summary>
	/// 析构函数
	/// </summary>
	~CProgressStatusBar()
	{
		std::for_each(m_progressBarList.begin(), m_progressBarList.end(),
						[](CProgressBarCtrlPair& pair) {
							delete pair.pProgressBarCtrl;
						});
	}

	/// <summary>
	/// 在状态栏中设置进度条
	/// </summary>
	/// <param name="nId">要放置进度条的状态栏面板Id</param>
	/// <param name="nMin">进度条最小值</param>
	/// <param name="nMax">进度条最大值</param>
	/// <returns>要放置进度条的状态栏面板Id</returns>
	BOOL SetProgressBar(UINT nId, UINT nMin, UINT nMax)
	{
		if (std::find_if(m_progressBarList.begin(), m_progressBarList.end(), 
							[nId](const CProgressBarCtrlPair& pair) {
								return pair.nPaneId == nId;
							}) != m_progressBarList.end())		// 查找指定Id的状态栏面板是否句柄进度条
				return FALSE;

		CRect rect;
		if (!GetPaneRect(nId, &rect))	// 获取指定面板的尺寸
			return FALSE;

		CProgressBarCtrl* pCtrl = new CProgressBarCtrl();	// 实例化进度条对象
		pCtrl->Create(*this, &rect, NULL, WS_CHILD | WS_VISIBLE);	// 创建进度条组件
		pCtrl->SetRange(nMin, nMax);	// 设置进度条范围
		CProgressBarCtrlPair pair = { nId, pCtrl };
		m_progressBarList.push_back(pair);	// 存储进度条组件
		return TRUE;
	}

	/// <summary>
	/// 获取进度条组件对象
	/// </summary>
	/// <param name="nId">状态栏面板Id</param>
	/// <returns>进度条组件对象指针</returns>
	CProgressBarCtrl* GetProcgressBar(UINT nId)
	{
		CProgressBarCtrlList::iterator iter = std::find_if(m_progressBarList.begin(), m_progressBarList.end(),
						[nId](const CProgressBarCtrlPair& pair) {
							return pair.nPaneId == nId;
						});		// 查找指定状态栏面板Id对应的进度条对象
		return iter == m_progressBarList.end() ? NULL : iter->pProgressBarCtrl;
	}

	/// <summary>
	/// 处理WM_SIZE消息
	/// </summary>
	/// <param name="nMsg">消息Id</param>
	/// <param name="wParam">消息参数</param>
	/// <param name="lParam">消息参数</param>
	/// <returns>消息执行结果</returns>
	LRESULT OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		LRESULT lRet = Base::OnSize(nMsg, wParam, lParam, bHandled);	// 调用超类的OnSize函数(必须提前调用,完成状态栏布局)
		std::for_each(m_progressBarList.begin(), m_progressBarList.end(),
						[&](CProgressBarCtrlPair& pair) {
							CRect rect;
							GetPaneRect(pair.nPaneId, &rect);
							pair.pProgressBarCtrl->MoveWindow(&rect);
						});	// 重新设置所有进度条的尺寸和位置
		return lRet;
	}

protected:
	
	CProgressBarCtrlList m_progressBarList;		// 保存进度条控件结构体的链表
};

调用

用起来很简单,先给状态栏设置足够多的面板,并给面板设置足够大的尺寸,设置进度条就可以了。

资源中添加状态栏面板Id

Resource.h

………… // 其它Id
#define IDPANE_STATUS			50000
#define IDPANE_CAPS_INDICATOR		50001
#define IDPANE_PROGRESS_BAR1		50002
#define IDPANE_PROGRESS_BAR2		50003

其中某些ID可以对应指定的字符串资源

项目名称.rc

STRINGTABLE
BEGIN
    IDPANE_STATUS           "状态"
    IDPANE_CAPS_INDICATOR   "大写"
END

框架窗口类代码如下:

FrameWnd.h

class CFrameWnd :
	public CFrameWindowImpl<CFrameWnd>,
	public CUpdateUI<CFrameWnd>,		
	public CMessageFilter,				
	public CIdleHandler					
{
public:
	/// <summary>
	/// 界面元素状态更新映射表
	/// </summary>
	BEGIN_UPDATE_UI_MAP(CFrameWnd)
		UPDATE_ELEMENT(0, UPDUI_STATUSBAR)
		UPDATE_ELEMENT(1, UPDUI_STATUSBAR)
		UPDATE_ELEMENT(3, UPDUI_STATUSBAR)
	END_UPDATE_UI_MAP()
	
	/// <summary>
	/// 消息映射表
	/// </summary>
	BEGIN_MSG_MAP_EX(CFrameWnd)
		…………	// 其它消息处理宏
		MSG_WM_CREATE(OnCreate)	// 窗体创建消息
		MSG_WM_TIMER(OnTimer)	// 定时器消息
		CHAIN_MSG_MAP(CFrameWindowImpl<CFrameWnd>)	// 将消息处理链接到CFrameWindowImpl基类
		CHAIN_MSG_MAP(CUpdateUI<CFrameWnd>)			// 将消息处理链接到CUpdateUI基类
	END_MSG_MAP()
	
	………… // 其它处理函数
	
	/// <summary>
	/// 处理空闲消息
	/// </summary>
	/// <returns>是否继续传递</returns>
	BOOL OnIdle();
	
	/// <summary>
	/// 处理窗口创建消息
	/// </summary>
	/// <param name="lpcs">指向窗口属性结构体的指针</param>
	/// <returns>0表示窗口创建成功,-1表示失败</returns>
	int OnCreate(LPCREATESTRUCT/* lpcs*/);
	
	/// <summary>
	/// 处理定时器消息
	/// </summary>
	/// <param name="nTimeId">定时器Id</param>
	void OnTimer(UINT_PTR nTimeId);
	
private:
	………… // 其它成员
	CProgressStatusBar m_statusBar;	// 多面板状态栏
};

FrameWnd.cpp

…………  // 其它处理函数

/// <summary>
/// 处理窗口创建消息
/// </summary>
/// <param name="lpcs">指向窗口属性结构体的指针</param>
/// <returns>0表示窗口创建成功,-1表示失败</returns>
int CFrameWnd::OnCreate(LPCREATESTRUCT/* lpcs*/)
{
	…………// 其它窗口创建代码
	
	m_hWndStatusBar = m_statusBar.Create(m_hWnd);		// 创建多面板状态栏
	int nPanes[] = { ID_DEFAULT_PANE, IDPANE_STATUS, IDPANE_PROGRESS_BAR1, IDPANE_CAPS_INDICATOR, IDPANE_PROGRESS_BAR2 };	// 定义状态栏面板数组
	m_statusBar.SetPanes(nPanes, sizeof(nPanes) / sizeof(*nPanes));	// 设置状态栏面板
	m_statusBar.SetPaneIcon(ID_DEFAULT_PANE, AtlLoadIconImage(IDR_MAINFRAME, LR_DEFAULTCOLOR, 16, 16));	// 为指定面板加入图标
	m_statusBar.SetPaneWidth(IDPANE_PROGRESS_BAR1, 100);
	m_statusBar.SetPaneWidth(IDPANE_PROGRESS_BAR2, 150);
	m_statusBar.SetProgressBar(IDPANE_PROGRESS_BAR1, 0, 100);
	m_statusBar.SetProgressBar(IDPANE_PROGRESS_BAR2, 0, 150);
	UIAddStatusBar(m_hWndStatusBar);	// 将状态栏纳入界面更新管理
	UpdateLayout();

	SetTimer(0, 100);	// 设置定时器

	return 0;
}

/// <summary>
/// 处理空闲消息
/// </summary>
/// <returns>是否进行了空闲处理</returns>
BOOL CFrameWnd::OnIdle()
{
	UISetText(1, CString(MAKEINTRESOURCE(IDPANE_STATUS))));
	if (GetKeyState(VK_CAPITAL) & 1)
		UISetText(3, CString(MAKEINTRESOURCE(IDPANE_CAPS_INDICATOR)));
	else
		UISetText(3, _T(""));

	UIUpdateMenuBar();
	UIUpdateToolBar();
	UIUpdateStatusBar();

	return FALSE;
}

/// <summary>
/// 处理定时器消息
/// </summary>
/// <param name="nTimeId">定时器Id</param>
void CFrameWnd::OnTimer(UINT_PTR nTimeId)
{
	int nMin, nMax;
	for (UINT nId = IDPANE_PROGRESS_BAR1; nId <= IDPANE_PROGRESS_BAR2; nId++)	// 遍历所有关联进度条的状态栏面板
	{
		CProgressBarCtrl* pCtrl = m_statusBar.GetProcgressBar(nId);	// 获取进度条对象
		if (pCtrl)
		{
			pCtrl->GetRange(nMin, nMax);	// 获取进度条范围
			// 设置进度条当前值
			if (pCtrl->GetPos() == nMax)
				pCtrl->SetPos(nMin);
			else
				pCtrl->SetStep(1);
			// 滚动进度条
			pCtrl->StepIt();
		}
	}
}

说明

在OnCreate函数中演示了如何在状态栏中加入进度条,在OnIdle函数中演示了如何使用状态栏,在OnTimer函数中演示了如何改变状态栏中的进度条值。七达网下载提供的这段代码使用了C++新特性,必须在C++11中才能执行(VS2012和VS2013均可)。执行结果如下:

一个显示进度条的WTL状态栏类

Tags:责任编辑:7down

软件评论

请自觉遵守互联网相关政策法规,评论内容只代表网友观点,与本站立场无关!

    登录   注册