// GradientProgressCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "VProgressCtrl.h"
//#include "MemDC.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
class CMemDC : public CDC
{
public:
CMemDC(CDC* pDC);
CMemDC* operator->(){return this;}
operator CMemDC*(){return this;}
virtual ~CMemDC();
private:
CBitmap m_bitmap;
CBitmap* m_pOldBitmap;
CDC* m_pDC;
CRect m_rect;
BOOL m_bMemDC;
};
CMemDC::CMemDC(CDC* pDC):CDC()
{
ASSERT(pDC!=NULL);
m_pDC=pDC;
m_pOldBitmap=NULL;
m_bMemDC=!pDC->IsPrinting();
//
if(m_bMemDC)
{
pDC->GetClipBox(&m_rect);
CreateCompatibleDC(pDC);
m_bitmap.CreateCompatibleBitmap(pDC,m_rect.Width(),m_rect.Height());
m_pOldBitmap=SelectObject(&m_bitmap);
SetWindowOrg(m_rect.left,m_rect.top);
}
else //为相关的现有设备准备打印
{
m_bPrinting=pDC->m_bPrinting;
m_hDC=pDC->m_hDC;
m_hAttribDC=pDC->m_hAttribDC;
}
}
CMemDC::~CMemDC()
{
if(m_bMemDC)
{
m_pDC->BitBlt(m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height(),
this,m_rect.left,m_rect.top,SRCCOPY);
SelectObject(m_pOldBitmap);
}
else
{
m_hDC=m_hAttribDC=NULL;
}
}
/////////////////////////////////////////////////////////////////////////////
// CVProgressCtrl
CVProgressCtrl::CVProgressCtrl()
: m_nTextType(TextCustom)
, m_strFormat(_T("%s"))
, m_nLower(0)
, m_nUpper(100)
, m_nCurrentPosition(0)
, m_nStep(1)
, m_clrStart(RGB(255,0,0))
, m_clrEnd(RGB(0,0,255))
, m_clrBkGround(GetSysColor(COLOR_3DFACE))
, m_clrText(RGB(255,255,255))
{
m_nLower=0;
m_nUpper=100;
m_nCurrentPosition=0;
m_nStep=10;
}
CVProgressCtrl::~CVProgressCtrl()
{
}
BEGIN_MESSAGE_MAP(CVProgressCtrl, CProgressCtrl)
//{{AFX_MSG_MAP(CVProgressCtrl)
ON_WM_ERASEBKGND()
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CVProgressCtrl message handlers
void CVProgressCtrl::SetRange(int nLower,int nUpper)
{
//This Function is to Set Range of the progress
m_nLower=nLower;
m_nUpper=nUpper;
m_nCurrentPosition=nLower;
CProgressCtrl::SetRange(nLower,nUpper);
}
int CVProgressCtrl::SetStep(int nStep)
{
m_nStep=nStep;
return (CProgressCtrl::SetStep(nStep));
}
BOOL CVProgressCtrl::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return TRUE;//CProgressCtrl::OnEraseBkgnd(pDC);
}
void CVProgressCtrl::DrawGradient(CPaintDC *pDC, const RECT &rectClient, const int &nMaxWidth)
{
RECT rectFill; //显示区域
float fStep; //每一步的幅宽
CBrush brush; //显示的颜色画刷
CMemDC memDC(pDC);
int r,g,b;
float rStep,gStep,bStep;
//得到不同颜色并相减,返回颜色之间的最大差值
r=(GetRValue(m_clrEnd)-GetRValue(m_clrStart));
g=(GetGValue(m_clrEnd)-GetGValue(m_clrStart));
b=(GetBValue(m_clrEnd)-GetBValue(m_clrStart));
//使进程条显示的总数 等于最大的颜色差值
int nSteps=max(abs(r),max(abs(g),abs(b)));
//确定每一颜色填充多大的矩形区域
fStep=(float)rectClient.right/(float)nSteps;
//设置每一颜色填充的步数
rStep=r/(float)nSteps;
gStep=g/(float)nSteps;
bStep=b/(float)nSteps;
r=GetRValue(m_clrStart);
g=GetGValue(m_clrStart);
b=GetBValue(m_clrStart);
//绘制颜色渐变的进程条
for(int iOnBand=0;iOnBand<nSteps;iOnBand++)
{
::SetRect(&rectFill,
//以下为填充矩形区域的左上角x,y和右下角x,y
(int)(iOnBand*fStep),
0,
(int)((iOnBand+1)*fStep),
rectClient.bottom+1);
VERIFY(brush.CreateSolidBrush(RGB(r+rStep*iOnBand,g+gStep*iOnBand,b+bStep*iOnBand)));
memDC.FillRect(&rectFill,&brush);
VERIFY(brush.DeleteObject());
//在结束绘制之前,使用背景色填充乘下的的客户区域
if(rectFill.right>nMaxWidth)
{
::SetRect(&rectFill,rectFill.right,0,rectClient.right,rectClient.bottom);
VERIFY(brush.CreateSolidBrush(m_clrBkGround));
memDC.FillRect(&rectFill,&brush);
VERIFY(brush.DeleteObject());
return;
}
}
}
void CVProgressCtrl::DrawProgressText(CPaintDC& dc,RECT& rectClient)
{
//根据文本类型,设置显示的文本
switch(m_nTextType)
{
case TextPercent:
m_strText.Format(m_strFormat,(int)(100*(float)m_nCurrentPosition/m_nUpper));
break;
case TextPos:
m_strText.Format(m_strFormat,m_nCurrentPosition);
break;
default://TextCustom
break;
}
//设置文本颜色
dc.SetTextColor(m_clrText);
dc.SetBkMode(TRANSPARENT);
//绘制文本
dc.DrawText(m_strText,&rectClient,DT_VCENTER|DT_CENTER|DT_SINGLELINE);
}
void CVProgressCtrl::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
if(m_nCurrentPosition<=m_nLower||m_nCurrentPosition>=m_nUpper)
{
CRect rect;
GetClientRect(rect);
CBrush brush;
brush.CreateSolidBrush(::GetSysColor(COLOR_3DFACE));
dc.FillRect(&rect,&brush);
VERIFY(brush.DeleteObject());
return;
}
CRect rectClient;
GetClientRect(rectClient);
float maxWidth((float)m_nCurrentPosition/(float)m_nUpper*(float)rectClient.right);
//绘制进度条
DrawGradient(&dc,rectClient,(int)maxWidth);
//绘制进度条文本
DrawProgressText(dc,rectClient);
// Do not call CProgressCtrl::OnPaint() for painting messages
}
int CVProgressCtrl::SetPos(int nPos)
{
//Set the Position of the Progress
m_nCurrentPosition = nPos;
return (CProgressCtrl::SetPos(nPos));
}
void CVProgressCtrl::SetText(LPCTSTR lpcszText)
{
m_strText.Format(m_strFormat,lpcszText);
this->Invalidate();
}
void CVProgressCtrl::SetTextType(int nTextType,LPCTSTR lpszFormat)
{
m_nTextType = nTextType;//文本类型
m_strFormat = lpszFormat;//文本格式化
int nIndex;//内容在格式化中的位置
if (m_strFormat.GetLength() == 0)
{
nIndex = 0;
}
else
{
int nTemp = m_strFormat.Find(_T("%s"));
if (nTemp == -1)
{
nIndex = m_strFormat.GetLength();
}
else
{
nIndex = nTemp;
m_strFormat.Delete(nTemp,2);
while ((nTemp = m_strFormat.Find(_T("%"),nTemp)) > -1)
{
m_strFormat.Insert(nTemp,_T("%"));
nTemp += 2;
}
}
}
//根据文本类型不同,设置格式化字符串
switch(m_nTextType)
{
case TextPercent:
m_strFormat.Insert(nIndex,_T("%d%%"));
break;
case TextPos:
m_strFormat.Insert(nIndex,_T("%d"));
break;
default:
m_strFormat.Insert(nIndex,_T("%s"));
break;
}
}
这个代码中为什么进度条到达100%后会重置为0