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

来源:互联网 发布:网络渗透用什么系统 编辑:程序博客网 时间:2024/06/07 13:44

引言

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

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

  这次需要用一个带进度条状态栏,以前也用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;// 进度条组件的IdCProgressBarCtrl* 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_STATUS50000#define IDPANE_CAPS_INDICATOR50001#define IDPANE_PROGRESS_BAR150002#define IDPANE_PROGRESS_BAR250003

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

项目名称.rc

STRINGTABLEBEGIN    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)));elseUISetText(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);elsepCtrl->SetStep(1);// 滚动进度条pCtrl->StepIt();}}}


说明

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


1 0
原创粉丝点击