天天看点

WTL 自绘控件库 (CQSProgressBar)

概述:

代码实现如下:

#pragma once;
#pragma warning(disable:4995 4819)

#include "QsInclude.h"
#include <vector>
using namespace std;

/*************************进度Style定义****************/
#define QS_PBS_SOLD        0x00000001       //实心进度条
#define QS_PBS_BLOCK    0x00000002       //块状进度条
#define QS_PBS_TXT         0x00000100      //自绘时文字显示进度
#define QS_PBS_RANGE        0x00000200      //绘制比例进度条
#define QS_PBS_IMAGE    0x00001000      //背景和前景图片来显示进度条
#define QS_PBS_COLOR    0x00002000      //背景和前景用颜色来显示进度条
#define QS_PBS_SYSTEM      0x00004000      //不自绘,使用系统的默认特性
/**********************************************************/
typedef struct  RangeClr
{
    Color   clr;
    float   rangepos;
}RangeClrName;

class CQSProgressBar :
   public CWindowImpl<CQSProgressBar, CProgressBarCtrl>,
    public CImageMgrCtrlBase< CQSProgressBar>
{
   typedef CWindowImpl< CQSProgressBar, CProgressBarCtrl > theBaseClass;
   typedef CImageMgrCtrlBase< CQSProgressBar> theImageCtrlBaseClass;

private:
   typedef struct stFONT
   {
      TCHAR szFamilyName[LF_FACESIZE];         // 字体名称, 如:宋体、微软雅黑等
      float fSize;                              // 字体大小
      FontStyle   nStyle;                       // 字体类型
      Unit  unit;                               // 字体的计量单位
   } FONT;
   FONT m_FontTxt;                 //显示进度百分比的字体
   COLORREF m_crBK;           // QS_PROBAR_STYLE_COLOR样式的文字颜色
   Color m_crFGfront;                  // QS_PROBAR_STYLE_COLOR样式的前景色 前景色为渐变色 
   Color m_crFGend;                  // QS_PROBAR_STYLE_COLOR样式的前景色
   COLORREF m_crtxt;          // QS_PROBAR_STYLE_COLOR样式的背景色
   DWORD m_QsStyle;           //QS的自绘的样式
   float FrontX;
   float EndX;
    vector<RangeClrName>   m_rangeVct;       //每部分比例
   LinearGradientMode m_LGMode;        //渐变方向
public:

    BEGIN_MSG_MAP( CQSProgressBar )
        MESSAGE_HANDLER( WM_PAINT, OnPaint )
        MESSAGE_HANDLER( WM_ERASEBKGND, OnEraseBKGnd )
        CHAIN_MSG_MAP( theImageCtrlBaseClass )
        DEFAULT_REFLECTION_HANDLER()
    END_MSG_MAP()

    /**
    *@method   CQSProgressBar
    *@brief    CQSProgressBar类构造函数
    *    
    *@return   
    */
    CQSProgressBar()
    {
        m_uFirstPos = CONTROL_PBS_FIRST;
        m_uLastPos = CONTROL_PBS_LAST;
      SetQSFont( _T("宋体"), 10, FontStyleRegular, UnitPoint );
      m_crBK = RGB(255, 255, 255);
      m_crFGfront = Color(220,0,188,40);
      m_crFGend = Color(100,0, 188, 100);
      m_crtxt = RGB(0, 255, 0);
      m_QsStyle = QS_PBS_SYSTEM;
      EndX = FrontX = 5;
      m_LGMode =LinearGradientModeVertical;
    }

    /**
    *@method   ~CQSProgressBar
    *@brief    CQSProgressBar析构造函数
    *    
    *@return   
    */
    virtual ~CQSProgressBar()
    {
    }

   /**
   *@method   Create
   *@brief    通过Create来创建窗口。
   *    
   *@param    HWND hWndParent
   *@param    ATL::_U_RECT rect = NULL
   *@param    LPCTSTR szWindowName = NULL
   *@param    DWORD dwStyle = 0
   *@param    DWORD dwExStyle = 0
   *@param    ATL::_U_MENUorID MenuOrID = 0U
   *@param    LPVOID lpCreateParam = NULL
   *@return   HWND
   */
   HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
      DWORD dwStyle = 0, DWORD dwExStyle = 0,
      ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
   {
      return theBaseClass::Create( hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, MenuOrID.m_hMenu, lpCreateParam);
   }

   /**
   *@method   SetFrontorEnd
   *@brief   设置前景图片的圆角的长度 
   *    
   *@param    float fFront
   *@param    float fEnd
   *@return   void
   */
   void SetFrontorEnd(float fFront,float fEnd)
    {
        FrontX = fFront;
        EndX = fEnd;
    }
   /**
   *@method   SetFrontX
   *@brief    SetFrontX设置前景图片的圆角的长度
   *    
   *@param    float fFront
   *@return   void
   */
   void SetFrontX(float fFront)
   {
      FrontX = fFront;
   }

   /**
   *@method   SetEndx
   *@brief    SetEndx设置前景图片的圆角最后的长度
   *    
   *@param    float fEnd
   *@return   void
   */
   void SetEndx(float fEnd)
   {
      EndX = fEnd;
   }

    /**
    *@method   SubclassWindow
    *@brief    类对象关联
    *    
    *@param    HWND hWnd  对象句柄
    *@return   BOOL  成功返回TRUE,失败返回FALSE
    */
    BOOL SubclassWindow( HWND hWnd )
    {
        BOOL bRet = theBaseClass::SubclassWindow( hWnd );
        ModifyStyleEx( WS_EX_APPWINDOW, 0 );
        return bRet;
    }

   /**
   *@method   SetQSFont
   *@brief    设置字体进度条显示字体
   *    
   *@param    TCHAR *szName 字体名称
   *@param    float fSize  字体大小
   *@param    FontStyle style  字体style
   *@param    Unit unit  字体显示单元
   *@return   BOOL  成功返回TRUE,失败返回FALSE
   */
   BOOL SetQSFont( TCHAR *szName, float fSize, FontStyle style, Unit unit )
   {
      _tcscpy_s( m_FontTxt.szFamilyName, LF_FACESIZE, szName );
      m_FontTxt.fSize = fSize;
      m_FontTxt.nStyle = style;
      m_FontTxt.unit = unit;
      return TRUE;
   }
   
   /**
   *@method   SetForColor
   *@brief    设置QS_PROBAR_STYLE_COLOR 
   *    
   *@param    Color crFGfront  设置前景的颜色1
   *@param    Color crFGend    设置前景的颜色2
   *@param    LinearGradientMode LGMode    的样式下的前景颜色
   *@return   void
   */
   void SetForColor( Color crFGfront,Color crFGend,LinearGradientMode LGMode)              
   {
      m_crFGfront = crFGfront;
      m_crFGend = crFGend;
      m_LGMode = LGMode;
   }
   
   /**
   *@method   SetBkColor
   *@brief    设置QS_PROBAR_STYLE_COLOR 的样式下的背景颜色
   *    
   *@param    COLORREF bkcolor 设置背景景的颜色
   *@return   void
   */
   void SetBkColor(COLORREF bkcolor)
   {
      m_crBK = bkcolor;
   }
   
   /**
   *@method   SetQSWindowsStyle
   *@brief    设置进度条的样式下的背景颜色
   *    
   *@param    DWORD nStyle 窗口的自绘样式
   *@return   void
   */
   void SetQSWindowsStyle(DWORD nStyle)
   {
      m_QsStyle = nStyle;
   }

    void SetPosRange(const vector<RangeClr> rangeClr)
    {
        m_rangeVct.clear();
        m_rangeVct = rangeClr;
    }
protected:

   /**
   *@method   DrawRect
   *@brief    进度条的矩形区域绘制
   *    
   *@param    Graphics* pGraphics 绘图对象
   *@param    Rect r  绘图区域
   *@param    Color ulclr  颜色值内圈
   *@param    Color brclr  外圈颜色值
   *@param    int width  外矩形框的宽度
   *@return   void  成功返回TRUE,失败返回FALSE
   */
   void DrawRect(Graphics* pGraphics, Rect r,  Color ulclr, Color brclr, int width)
   {
      int i = 0;
      int left = 0;
      int top =0;
      int bottom =0;
      int right =0;

      // disable smoothing mode
      SmoothingMode oldMode = pGraphics->GetSmoothingMode();
      pGraphics->SetSmoothingMode(SmoothingModeNone);

      // define the upper left pen
      Pen ulpen(ulclr, 1); 
      ulpen.SetAlignment(PenAlignmentCenter);

      // define the bottom right pen
      Pen brpen(brclr, 1); 
      brpen.SetAlignment(PenAlignmentCenter);

      // not sure why
      Rect rc(r); 

      for(i = 0; i < width; i++)
      {
         left = rc.X; top = rc.Y; bottom = rc.GetBottom()-1; right = rc.GetRight()-1;
         if((i%2)==0)
         {
            // left
            pGraphics->DrawLine(&ulpen, left, top, left, bottom);

            // top
            pGraphics->DrawLine(&ulpen, left, top, right, top);

            // right
            pGraphics->DrawLine(&ulpen, right, top+1, right, bottom);

            // bottom
            pGraphics->DrawLine(&ulpen, left+1, bottom, right, bottom);
         }
         else
         {
            // left
            pGraphics->DrawLine(&brpen, left, top, left, bottom);

            // top
            pGraphics->DrawLine(&brpen, left, top, right, top);

            // right
            pGraphics->DrawLine(&brpen, right, top+1, right, bottom);

            // bottom
            pGraphics->DrawLine(&brpen, left+1, bottom, right, bottom);
         }
         rc.Inflate(-1, -1);
      }

      // restore smoothing mode
      pGraphics->SetSmoothingMode(oldMode);

   }
   
   /**
   *@method   DrawNormalProgressBar
   *@brief    绘制普通颜色填充的进度条函数
   *    
   *@return   void
   */
   void DrawNormalProgressBar()
   {
      // 获得作图区域

      CRect rtBar;
      GetWindowRect(&rtBar);

       WTL::CPaintDC paintDC( m_hWnd );
       paintDC.SetBkMode( TRANSPARENT );
        WTL::CDC dc;
        dc.CreateCompatibleDC( paintDC.m_hDC );
        WTL::CBitmap memBitmap;
        memBitmap.CreateCompatibleBitmap( paintDC.m_hDC, rtBar.Width(), rtBar.Height() );
        HBITMAP hOldBmp = dc.SelectBitmap( memBitmap );
        dc.SetBkMode( TRANSPARENT );

       Graphics graph( dc.m_hDC );
      // 画背景
      SolidBrush lgbr(Color(255, GetRValue(m_crBK), GetGValue(m_crBK), GetBValue(m_crBK)));
      graph.FillRectangle(&lgbr, 0, 0, rtBar.Width(), rtBar.Height());

         Image *pImage = GetImage( CONTROL_PBS_BACKIMG );
         if(pImage != NULL)
         {
             graph.DrawImage( pImage,RectF ( (REAL)0.0, (REAL)0.0, (REAL)rtBar.Width(), (REAL)rtBar.Height() ),0, (REAL)0, (REAL)pImage->GetWidth(), (REAL)pImage->GetHeight(), UnitPixel ); 
         }


      Rect rect(0,0,rtBar.Width(),rtBar.Height());
      DrawRect(&graph,rect,Color(200,190,190,190),Color(240,104, 104, 104),1); //绘外框区域

      // 画进度 
      UINT pos = GetPos();
      int maxPos = 0;
      int minPos = 0;
      GetRange( minPos, maxPos );
      float fRatio = ( (float) pos - (float )minPos) / ( (float)maxPos - (float )minPos );
      //SolidBrush sbFG(Color(160, GetRValue(m_crFG), GetGValue(m_crFG), GetBValue(m_crFG)));
      
      REAL positions[] = { 0.0f, 1.0f};

      Color colors[2] ={m_crFGfront,m_crFGend};

      Rect rectF(rtBar.left,rtBar.top,rtBar.Width(),rtBar.Height());
      //LinearGradientBrush lgbr(rectF, Color(RGB(255,255,255)), Color(RGB(255,255,255)), m_LGMode);
      //lgbr.SetInterpolationColors(colors, positions, 2);
      REAL rWidth = 10;
      //REAL rHeight = (REAL)(rtBar.Height());
      RectF rtfFG;
      rtfFG.X = 0;
      rtfFG.Y = 0;
      
      if(m_QsStyle&QS_PBS_SOLD)
      {
         rtfFG.Width = (rtBar.Width()) * fRatio;
         rtfFG.Height = (REAL)rtBar.Height() - 4;
         graph.FillRectangle(&lgbr, rtfFG);
      }

      if(m_QsStyle&QS_PBS_BLOCK)
      {
         rtfFG.Width = (REAL)(rWidth * 0.8);
         rtfFG.Height = (REAL)(rtBar.Height())-4;
         while((rtfFG.X + rtfFG.Width) < (rtBar.Width() * fRatio))
         {
            graph.FillRectangle(&lgbr, rtfFG);
            rtfFG.X += rWidth;
         }
         if(pos!=0) //多绘一个
         {
            graph.FillRectangle(&lgbr, rtfFG);
         }
      }
      if(m_QsStyle&QS_PBS_TXT)
      {
         DrawText(pos,maxPos,graph,rtBar);
      }
        if (m_QsStyle&QS_PBS_RANGE)
        {
            rtfFG.X = 1;
            rtfFG.Y = 1;
            //绘制比例进度条
            for (vector<RangeClr>::iterator pos = m_rangeVct.begin();pos != m_rangeVct.end();pos ++)
            {
                colors[0] = pos->clr;
                lgbr.SetColor(colors[0]);
                //lgbr.SetInterpolationColors(colors,positions,2);
                rtfFG.Width = (rtBar.Width())*(pos->rangepos);
                rtfFG.Height = (REAL)rtBar.Height() - 1;
                graph.FillRectangle(&lgbr,rtfFG);

                rtfFG.X += (int)(rtBar.Width())*(pos->rangepos);
            }

        }
      graph.ReleaseHDC( dc.m_hDC );
     // 提交图像
      paintDC.BitBlt( 0, 0, rtBar.Width(), rtBar.Height(), dc.m_hDC, 0, 0, SRCCOPY );
       dc.SelectBitmap( hOldBmp );
      memBitmap.DeleteObject();
      dc.DeleteDC();

   }
   
   /**
   *@method   DrawImageProgressBar
   *@brief    绘制图片填充的进度条函数
   *    
   *@return   void
   */
   void DrawImageProgressBar()
   {
      CRect rtBar;
      GetWindowRect(&rtBar);

      WTL::CPaintDC paintDC( m_hWnd );
      paintDC.SetBkMode( TRANSPARENT );
      WTL::CDC dc;
      dc.CreateCompatibleDC( paintDC.m_hDC );
      WTL::CBitmap memBitmap;
      memBitmap.CreateCompatibleBitmap( paintDC.m_hDC, rtBar.Width(), rtBar.Height() );
      HBITMAP hOldBmp = dc.SelectBitmap( memBitmap );
      dc.SetBkMode( TRANSPARENT );
      ::SendMessage( GetParent(), WM_DRAWBKGNDUI, ( WPARAM )dc.m_hDC, ( LPARAM )m_hWnd);

      Graphics graph( dc.m_hDC );
      // 画背景
      ColorMatrix HotMat = {  1.05f, 0.00f, 0.00f, 0.00f, 0.00f,
         0.00f, 1.05f, 0.00f, 0.00f, 0.00f,
         0.00f, 0.00f, 1.05f, 0.00f, 0.00f,
         0.00f, 0.00f, 0.00f, 1.00f, 0.00f,
         0.05f, 0.05f, 0.05f, 0.00f, 1.00f   };       //光照矩阵

      ImageAttributes ia;
      ia.SetColorMatrix(&HotMat);

      Image *pImage = GetImage( CONTROL_PBS_BACKIMG );
      if(pImage != NULL)
      {
         graph.DrawImage( pImage,RectF ( (REAL)0.0, (REAL)0.0, (REAL)rtBar.Width(), (REAL)rtBar.Height() ),0, (REAL)0, (REAL)pImage->GetWidth(), (REAL)pImage->GetHeight(), UnitPixel ); 
      }
       
      // 画进度 

       int pos = GetPos();
       int maxPos = 0;
      int minPos = 0;
       GetRange( minPos, maxPos );
      if(maxPos>0) //只有MAX大于1是才绘制前景
      {
         /对除零处理
         float fared=  (float)maxPos - (float )minPos;
         if(fared<0.0001) //
         {
            fared = 1.0f;
         }
         float fRatio = ( (float) pos - (float )minPos) / fared;

         REAL rWidth = 10;
         //REAL rHeight = (REAL)(rtBar.Height());
         RectF rtfFG;
         rtfFG.X = 0;
         rtfFG.Y = 0;

         Image *pImageFront = GetImage(CONTROL_PBS_FRONTIMGFRONT);
         Image *pImageEnd = GetImage(CONTROL_PBS_FRONTIMGEND);
         pImage = GetImage( CONTROL_PBS_FRONTIMG );
         if(m_QsStyle&QS_PBS_SOLD)
         {
            if((pos>=1))
            {  
               rtfFG.Width = (rtBar.Width()) * fRatio+FrontX;
               if(pImageFront != NULL)
               {
                  graph.DrawImage( pImageFront, RectF((REAL)0,(REAL)0,(REAL)FrontX,(REAL)rtBar.Height()), 0.0, 0.0, (REAL)pImageFront->GetWidth(), ( float ) pImageFront->GetHeight(), UnitPixel,&ia);
               }
            }
            if((pos>2&&pos<maxPos)||(pos==maxPos))
            {
               rtfFG.X = rtfFG.X +FrontX;
               rtfFG.Width = (REAL)((rtBar.Width()) * fRatio-EndX*1.5);
               rtfFG.Height = (REAL)rtBar.Height();
               if(pImage != NULL)
               {
                  graph.DrawImage( pImage, rtfFG, 0.0, 0.0, (REAL)pImage->GetWidth(), ( float ) pImage->GetHeight(), UnitPixel,&ia );
               }
            }

            if(pos==maxPos)
            {
               if(pImageEnd != NULL)
               {
                  graph.DrawImage( pImageEnd, RectF( (REAL)(rtBar.Width()) -EndX,(REAL)0,EndX,(REAL)rtBar.Height()), 0.0, 0.0, (REAL)pImageEnd->GetWidth(), ( float ) pImageEnd->GetHeight(), UnitPixel ,&ia);

               }
            }
         }
         if(m_QsStyle&QS_PBS_BLOCK)
         {
            if(pos>=1)
            {
               rtfFG.Width = (rtBar.Width()) * fRatio+FrontX;
               graph.DrawImage( pImageFront, RectF((REAL)0,(REAL)0,FrontX,(REAL)rtBar.Height()), 0.0, 0.0, (REAL)pImageFront->GetWidth(), ( float ) pImageFront->GetHeight(), UnitPixel );
               rtfFG.X = rtfFG.X+FrontX;
               rtfFG.X += 2;
            }
            
            rtfFG.Width = (REAL)(rWidth * 0.8);
            rtfFG.Height = (REAL)(rtBar.Height());
            while((rtfFG.X + rtfFG.Width) < (rtBar.Width() * fRatio))
            {
               if(pImageFront != NULL)
               {
                 graph.DrawImage( pImage, rtfFG, 0.0, 0.0, (REAL)pImage->GetWidth(), ( float ) pImage->GetHeight(), UnitPixel);
                 
                 rtfFG.X += rWidth;
               }
            }
            if(pos==maxPos)
            {
               if(pImageEnd != NULL)
               {
                  graph.DrawImage( pImageEnd, RectF(float(rtfFG.X),float(0),FLOAT(rtBar.Width()-rtfFG.X),(REAL)rtBar.Height()), 0.0, 0.0, (REAL)pImageEnd->GetWidth(), ( float ) pImageEnd->GetHeight(), UnitPixel );
               }
            }

         }
         if(m_QsStyle&QS_PBS_TXT)
         {
            DrawText(pos,maxPos,graph,rtBar);
         }     
         graph.ReleaseHDC( dc.m_hDC );
      }
      //提交图像
      paintDC.BitBlt( 0, 0, rtBar.Width(), rtBar.Height(), dc.m_hDC, 0, 0, SRCCOPY );
      dc.SelectBitmap( hOldBmp );
      memBitmap.DeleteObject();
      dc.DeleteDC();
   }

   /**
   *@method   DrawText
   *@brief    绘制进度条的百分比字体只是对
   *    
   *@param    int pos  当前进度条的位置
   *@param    int Maxpos  进度条的最大值
   *@param    Graphics& graph  绘图对象
   *@param    CRect rect  绘图区域
   *@return   void
   */
   void DrawText(int pos,int Maxpos,Graphics& graph,CRect rect)
   {
      Gdiplus::Font font( m_FontTxt.szFamilyName, m_FontTxt.fSize, m_FontTxt.nStyle,m_FontTxt.unit);

      StringFormat strFormat;          
      strFormat.SetAlignment( StringAlignmentNear );              // 设置横向对齐方式
      strFormat.SetLineAlignment( StringAlignmentCenter );        // 设置纵向对齐方式
      float fPos = float(pos);
      int iPcent = int(float (fPos/Maxpos)*100);
      CString strTxt = _T("");
      strTxt.Format(_T( "%d" ),iPcent);
      strTxt =strTxt+_T("%");
      INT nLength = strTxt.GetLength();
      SolidBrush brush( Color( 254, GetRValue(m_crtxt), GetGValue(m_crtxt), GetBValue(m_crtxt)) );
      graph.DrawString(strTxt, (INT)nLength, &font,RectF( (float)rect.Width()/2, (float)0, (float)rect.Width(), (float)rect.Height() ),&strFormat, &brush );
   }
    
    /**
    *@method   OnPaint
    *@brief    绘制消息函数
    *    
    *@param    UINT uMsg   消息类型
    *@param    WPARAM wParam  未被使用
    *@param    LPARAM lParam  详见MSDN
    *@param    BOOL& bHandled 未被使用
    *@return   LRESULT
    */
    LRESULT OnPaint( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
    {
      if(m_QsStyle&QS_PBS_SYSTEM)
      {
            return DefWindowProc( uMsg, wParam, lParam );
      }
      if(m_QsStyle&QS_PBS_COLOR)
      {
         DrawNormalProgressBar();
      }
      if(m_QsStyle&QS_PBS_IMAGE)
      {
         DrawImageProgressBar();
      }
        return 0;
    }

    /**
    *@method   OnEraseBKGnd
    *@brief    背景绘制消息函数
    *    
    *@param    UINT uMsg  消息类型
    *@param    WPARAM wParam 未被使用
    *@param    LPARAM lParam 详见MSDN
    *@param    BOOL& bHandled  未被使用
    *@return   LRESULT
    */
    LRESULT OnEraseBKGnd( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
    {
      return DefWindowProc(uMsg, wParam, lParam);
    }
};