很多時候我們都要在UI上顯示事件的進度資訊,MFC也提供了現成的進度條控件CProgressCtrl,隻要在UI上放置一個CProgressCtrl控件,然後在程式中調用SetRange和SetPos方法就可以顯示進度資訊了。但是MFC自帶的控件并不是完美的,例如它無法顯示文字進度,如“50%”等,隻能通過進度條的位置大緻判斷目前的進度,如果需要詳細的進度,通常還要放置一個Static控件單獨顯示這個百分号的進度。如果要在進度條上顯示文字資訊,就需要自己繪制進度條的UI了,下面我提供一個簡單單但很實用的方法來滿足要求。效果圖如下:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnauEDM1cTMzIDMx8CXzAzMxAjMvwFduVWboNWY0RXYvwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.jpg)
首先,需要添加一個MFC類CMyProgress,繼承自CprogressCtrl,這樣,我們的進度條控件就具有了标準工具條的特性。為了能夠反映進度資訊以及繪制進度條,需要在類中添加如下變量:
COLORREF m_prgsColor; //進度條進度部分顔色
COLORREF m_freeColor; //進度條後面空餘部分顔色
COLORREF m_prgsTextColor; //進度部分字型顔色
COLORREF m_freeTextColor; //空白部分字型顔色
int m_iMin; //進度條的最小值,通常是0
int m_iMax; //進度條的最大值,通常是100
int m_iPos; //目前的進度
int m_nBarWidth; //進度條寬度
然後需要給調用者提供操作接口,标準的接口包括SetRange、SetPos,當然還可以提供諸如設定顔色、設定文字等方法,這個很簡單,就不在這裡給出代碼了。
int CMyProgress::SetPos(int nPos)
{
if (!::IsWindow(m_hWnd))
{
return -1;
}
int nOldPos = m_iPos;
m_iPos = nPos;
CRect rect;
GetClientRect(rect);
//這裡先計算要顯示的進度條寬度,避免對同一進度多次繪制視窗
double Fraction = (double)(m_iPos - m_iMin) / ((double)(m_iMax - m_iMin));
int nBarWidth = (int) (Fraction * rect.Width());
if (nBarWidth != m_nBarWidth)
m_nBarWidth = nBarWidth;
RedrawWindow();
return nOldPos;
}
void CMyProgress::SetRange(int nLower, int nUpper)
m_iMax = nUpper;
m_iMin = nLower;
m_iPos = m_iMin;
m_nBarWidth = 0;
最後也是最重要的操作是如何繪制進度條,這需要處理WM_PAINT消息,通過VS2010或VC等我們可以很友善的添加WM_PAINT的消息處理函數,當然我們也可以自己手動在程式添加。首先,在CMyProgress中聲明如下函數:
afx_msg void OnPaint();
然後,在CMyProgress類的定義檔案中找到消息映射BEGIN_MESSAGE_MAP,然後添加映射:
BEGIN_MESSAGE_MAP(CMyProgress, CProgressCtrl)
ON_WM_PAINT()
END_MESSAGE_MAP()
OnPaint的實作方法如下:
void CMyProgress::OnPaint()
//首先判斷設定是否有效
if (m_iMin >= m_iMax)
return;
CPaintDC dc(this); // device context for painting
// 不為繪圖消息調用 CProgressCtrl::OnPaint()
//擷取有效的進度條的位置和大小
CRect LeftRect, RightRect, ClientRect;
GetClientRect(ClientRect);
LeftRect = RightRect = ClientRect;
//計算顯示進度的比例
//繪制整個進度條中的有效進度
LeftRect.right = LeftRect.left + (int)((LeftRect.right - LeftRect.left) * Fraction);
dc.FillSolidRect(LeftRect, m_prgsColor);
//繪制剩餘進度
RightRect.left = LeftRect.right;
dc.FillSolidRect(RightRect, m_freeColor);
CString str;
str.Format(_T("%d%%"), (int)(Fraction*100.0));
//設定文字背景顔色為透明
dc.SetBkMode(TRANSPARENT);
//為了能夠在進度和剩餘進度中顯示不同顔色的字型,需要分别設定兩邊的字型顔色并繪圖
CRgn rgn;
rgn.CreateRectRgn(LeftRect.left, LeftRect.top, LeftRect.right, LeftRect.bottom);
dc.SelectClipRgn(&rgn);
dc.SetTextColor(m_prgsTextColor);
dc.DrawText(str, ClientRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);