天天看點

MFC帶文字顯示的進度條

        很多時候我們都要在UI上顯示事件的進度資訊,MFC也提供了現成的進度條控件CProgressCtrl,隻要在UI上放置一個CProgressCtrl控件,然後在程式中調用SetRange和SetPos方法就可以顯示進度資訊了。但是MFC自帶的控件并不是完美的,例如它無法顯示文字進度,如“50%”等,隻能通過進度條的位置大緻判斷目前的進度,如果需要詳細的進度,通常還要放置一個Static控件單獨顯示這個百分号的進度。如果要在進度條上顯示文字資訊,就需要自己繪制進度條的UI了,下面我提供一個簡單單但很實用的方法來滿足要求。效果圖如下:

MFC帶文字顯示的進度條

    首先,需要添加一個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);