好久没用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; // 进度条组件的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
项目名称.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; // 多面板状态栏 };
………… // 其它处理函数 /// <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均可)。执行结果如下:
原文:http://blog.csdn.net/mousebaby808/article/details/19198553