现在做的软件上要用图形来显示串口传过来的信号值大小,最简单的办法,莫过于用进度条显示了。但是在使用的过程中发现一个问题,就是没有刻度。如果有美工,问题也好解决,在没有美工的情况下,只好靠自己动手DIY了。
由于以前没有做过控件,就在网上找了别人做的拿来参考,于是,就发现了颜色渐变进度条的代码。这个代码严格说来并不完全,进度条只能横着不能竖起来。在读懂了颜色渐变进度条后,我做出了带刻度的进度条控件。目前,我做的这个控件有以下功能:
1、设置前景色
2、设置背景色
3、设置有无刻度,刻度位置,刻度数量
4、设置进度条有无边框
5、设置文字显示
头文件如下:
#if !defined(AFX_GRADIENTPROGRESSCTRL_H__91ECB8BC_A7DA_42EB_B2C5_37419D31B753__INCLUDED_)
#define AFX_GRADIENTPROGRESSCTRL_H__91ECB8BC_A7DA_42EB_B2C5_37419D31B753__INCLUDED_
#endif
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#if !defined(AFX_MEMDC_H__A68B97E6_DDB4_4B4F_8A18_429844C3659C__INCLUDED_)
#define AFX_MEMDC_H__A68B97E6_DDB4_4B4F_8A18_429844C3659C__INCLUDED_
#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;
};
/
// CScaleProgressCtrl window
class CScaleProgressCtrl : public CProgressCtrl
{
// Construction
public:
CScaleProgressCtrl();
//Set_function
void SetTextColor(COLORREF color) {m_clrText=color;} //设置文字颜色,默认为
void SetBkColor(COLORREF color) {m_clrBkGround=color;} //设置进度条背景色
void SetForeColor(COLORREF color) {m_FaceColor=color;} //设置进度条前景色
void SetShowFrame(BOOL frame) {m_Frame=frame;} //设置是否显示进度条边框
//void SetEndColor(COLORREF color) {m_clrEnd=color;}
//Percent TXT showed in the Progress
void SetShowPercent(BOOL bShowPercent=TRUE) {m_bShowPercent=bShowPercent;} //是否显示文字
//Get_Function
COLORREF GetTextColor(void) {return m_clrText;}
COLORREF GetBkColor(void) {return m_clrBkGround;}
COLORREF GetFaceColor(void) {return m_FaceColor;}
// Attributes
public:
int m_nLower; //setrange的最小值
int m_nUpper; //setrange的最大值
int m_nStep; //步长
int m_nCurrentPosition; //setpos的值
COLORREF m_FaceColor,m_clrBkGround,m_clrText; //前景色,背景色,文字颜色的变量
BOOL m_bShowPercent; //是否显示文字的变量
BOOL m_ScaleLine; //有无刻度
int m_Side; //刻度的方向,如0表示左边或上边有刻度,1表示右边或下边有刻度,3表示两边都有
int m_ScaleNumber; //刻度的数量
BOOL m_Frame; //有无边框
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CScaleProgressCtrl)
//}}AFX_VIRTUAL
// Implementation
public:
int SetPos(int nPos);
void SetShowScale(BOOL Scaleline,int side,int scalenumber); //Scaleline是是否有刻度线,false为无刻度,true为有刻度
//side代表刻度的位置,当竖着时,0表示左边有刻度,1表示右边有刻度,3表示两边都有
//当水平时,0表示上边有刻度,1表示下边有刻度,3表示两边都有
//scalenumber表示刻度数量,直从3~setrange的最大值
int SetStep(int nStep); //设置步长
void SetRange(int nLower,int nUpper);
virtual ~CScaleProgressCtrl();
// Generated message map functions
protected:
void DrawGradient(CPaintDC *pDC, RECT& rectClient,const int & nMaxWidth); //水平时进度条的绘制
void DrawEndUp(CPaintDC *pDC, RECT& rectClient,const int & maxHigh); //竖直时进度条的绘制
//{{AFX_MSG(CScaleProgressCtrl)
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
public:
virtual BOOL Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
public:
virtual BOOL CreateEx(DWORD dwExStyle, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual void PreSubclassWindow();
};
cpp文件如下:
// ScaleProgressCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "ScaleProgressCtrl.h"
#include "assert.h"
//#include "MemDC.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//
// Construction/Destruction
//
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;
}
}
/
// CScaleProgressCtrl
CScaleProgressCtrl::CScaleProgressCtrl()
{
m_nLower=0; //setrange最小值
m_nUpper=100; //setrange最大值
m_nCurrentPosition=0; //setpos的值
m_nStep=10; //setstep的值
m_ScaleLine=false; //默认无刻度
m_ScaleNumber=10; //默认10个刻度线
m_Side=0; //默认水平时上边有刻度或竖直时左边有刻度
m_Frame=true; //默认无边框
//Initial Color of show
m_FaceColor= COLORREF(RGB(0,0,255));
//m_clrEnd= COLORREF(RGB(255,0,0));
m_clrBkGround=::GetSysColor(COLOR_3DFACE);
m_clrText=RGB(255,255,255); //默认文字颜色为白色
//Not show Word
m_bShowPercent=FALSE;
}
CScaleProgressCtrl::~CScaleProgressCtrl()
{
}
BEGIN_MESSAGE_MAP(CScaleProgressCtrl, CProgressCtrl)
//{{AFX_MSG_MAP(CScaleProgressCtrl)
ON_WM_ERASEBKGND()
ON_WM_PAINT()
//}}AFX_MSG_MAP
ON_WM_CREATE()
END_MESSAGE_MAP()
/
// CScaleProgressCtrl message handlers
void CScaleProgressCtrl::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 CScaleProgressCtrl::SetStep(int nStep)
{
m_nStep=nStep;
return (CProgressCtrl::SetStep(nStep));
}
BOOL CScaleProgressCtrl::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return TRUE;//CProgressCtrl::OnEraseBkgnd(pDC);
}
void CScaleProgressCtrl::DrawEndUp(CPaintDC *pDC, RECT &rectClient, const int &maxHigh)
{
RECT rectFill; //显示区域
float fStep; //每一步的幅长
CBrush brush; //显示的颜色画刷
CMemDC memDC(pDC);
CRect a1,b1;
if(m_ScaleLine==TRUE)
{
if(m_Side==0)
rectClient.left+=5;
if(m_Side==1)
rectClient.right-=5;
if(m_Side==2)
{
rectClient.left+=5;
rectClient.right-=5;
}
a1.top=rectClient.top;
a1.right=rectClient.left;
a1.bottom=rectClient.bottom;
a1.left=rectClient.left-5;
b1.top=rectClient.top;
b1.right=rectClient.right+5;
b1.bottom=rectClient.bottom;
b1.left=rectClient.right;
}
int nSteps=abs(m_nUpper-m_nLower);
fStep=(float)(abs(rectClient.top-rectClient.bottom))/(float)(m_nUpper-m_nLower);
//使用背景色填充客户区域
::SetRect(&rectFill,
//以下为填充矩形区域的左上角x,y和右下角x,y
rectClient.left, //左上X
rectClient.top,
rectClient.right, //右下X
rectClient.bottom); //右下Y
VERIFY(brush.CreateSolidBrush(m_clrBkGround));
memDC.FillRect(&rectFill,&brush); //填充背景色
VERIFY(brush.DeleteObject());
if(m_ScaleLine==TRUE)
{
COLORREF colorside;
colorside=::GetSysColor(COLOR_3DFACE);
VERIFY(brush.CreateSolidBrush(colorside));
memDC.FillRect(&a1,&brush);
memDC.FillRect(&b1,&brush);
VERIFY(brush.DeleteObject());
}
//绘制进程条
//if(rectFill.bottom>=maxHigh)
//{
::SetRect(&rectFill,rectFill.left,rectClient.bottom-m_nCurrentPosition*fStep,rectClient.right,rectClient.bottom);
VERIFY(brush.CreateSolidBrush(m_FaceColor));
memDC.FillRect(&rectFill,&brush);
VERIFY(brush.DeleteObject());
if(m_ScaleLine==TRUE)
{
COLORREF colorside;
colorside=::GetSysColor(COLOR_3DFACE);
VERIFY(brush.CreateSolidBrush(colorside));
memDC.FillRect(&a1,&brush);
memDC.FillRect(&b1,&brush);
VERIFY(brush.DeleteObject());
int m_step;
m_step=(rectClient.bottom-rectClient.top-1)/m_ScaleNumber; //这里不-1可能会有一个刻度绘不上最下边的或最右边的
int temp=abs(rectClient.top-rectClient.bottom);
for(int y=rectClient.bottom-1;y>=0;y-=m_step) //绘制刻度线
{
if(m_Side==0)
{
memDC.MoveTo(0,y);
memDC.LineTo(5,y);
}
if(m_Side==1)
{
memDC.MoveTo(rectClient.right,y);
memDC.LineTo(rectClient.right+5,y);
}
if(m_Side==2)
{
memDC.MoveTo(0,y);
memDC.LineTo(5,y);
memDC.MoveTo(rectClient.right,y);
memDC.LineTo(rectClient.right+5,y);
}
}
//}
return;
}
}
void CScaleProgressCtrl::DrawGradient(CPaintDC *pDC, RECT &rectClient, const int &nMaxWidth)
{
RECT rectFill; //显示区域
float fStep; //每一步的幅长
CBrush brush; //显示的颜色画刷
CMemDC memDC(pDC);
CRect a1,b1;
if(m_ScaleLine==TRUE)
{
if(m_Side==0)
rectClient.top+=5;
if(m_Side==1)
rectClient.bottom-=5;
if(m_Side==2)
{
rectClient.top+=5;
rectClient.bottom-=5;
}
a1.top=rectClient.top-5;
a1.left=rectClient.left;
a1.bottom=rectClient.top;
a1.right=rectClient.right;
b1.top=rectClient.bottom;
b1.right=rectClient.right;
b1.bottom=rectClient.bottom+5;
b1.left=rectClient.left;
}
int nSteps=abs(m_nUpper-m_nLower); //总步数
fStep=(float)(abs(rectClient.right-rectClient.left))/(float)(m_nUpper-m_nLower); //每步的坐标数
//使用背景色填充客户区域
::SetRect(&rectFill,
//以下为填充矩形区域的左上角x,y和右下角x,y
rectClient.left, //左上X
rectClient.top, //左上Y
rectClient.right, //右下X
rectClient.bottom); //右下Y
VERIFY(brush.CreateSolidBrush(m_clrBkGround));
memDC.FillRect(&rectFill,&brush); //填充背景色
VERIFY(brush.DeleteObject());
if(m_ScaleLine==TRUE)
{
COLORREF colorside;
colorside=::GetSysColor(COLOR_3DFACE);
VERIFY(brush.CreateSolidBrush(colorside));
memDC.FillRect(&a1,&brush);
memDC.FillRect(&b1,&brush);
VERIFY(brush.DeleteObject());
}
//绘制进程条
if(rectFill.right>=nMaxWidth)
{
::SetRect(&rectFill,rectFill.left,rectClient.top,rectClient.left+m_nCurrentPosition*fStep,rectClient.bottom);
VERIFY(brush.CreateSolidBrush(m_FaceColor));
memDC.FillRect(&rectFill,&brush);
VERIFY(brush.DeleteObject());
if(m_ScaleLine==TRUE)
{
COLORREF colorside;
colorside=::GetSysColor(COLOR_3DFACE);
VERIFY(brush.CreateSolidBrush(colorside));
memDC.FillRect(&a1,&brush);
memDC.FillRect(&b1,&brush);
VERIFY(brush.DeleteObject());
int m_step;
m_step=(rectClient.right-rectClient.left-1)/m_ScaleNumber; //刻度的步长
int temp=abs(rectClient.right-rectClient.left);
for(int x=0;x<=temp;x+=m_step) //绘制刻度线
{
if(m_Side==0)
{
memDC.MoveTo(x,0);
memDC.LineTo(x,5);
}
if(m_Side==1)
{
memDC.MoveTo(x,rectClient.bottom);
memDC.LineTo(x,rectClient.bottom+5);
}
if(m_Side==2)
{
memDC.MoveTo(x,0);
memDC.LineTo(x,5);
memDC.MoveTo(x,rectClient.bottom);
memDC.LineTo(x,rectClient.bottom+5);
}
}
}
return;
}
}
void CScaleProgressCtrl::OnPaint()
{
if(!m_Frame)
{
this->ModifyStyleEx(WS_EX_STATICEDGE,0);
this->Invalidate(false); //这两句是去掉Progress的边框并显示
}
DWORD y=this->GetStyle();
y=y&4;
CPaintDC dc(this); // device context for painting
CRect rectClient;
GetClientRect(rectClient);
float maxWidth((float)m_nCurrentPosition/(float)m_nUpper*(float)rectClient.right);
float maxHigh((float)m_nCurrentPosition/(float)m_nUpper*(float)rectClient.bottom);
//绘制
if(y==4)
DrawEndUp(&dc,rectClient,(int)maxHigh);
if(y==0)
DrawGradient(&dc,rectClient,(int)maxWidth);
//显示进程条进度文字
if(m_bShowPercent)
{
CString percent;
percent.Format("%d%%",(int)(100*(float)m_nCurrentPosition/m_nUpper)); //显示当前值的百分比
dc.SetTextColor(m_clrText);
dc.SetBkMode(TRANSPARENT);
dc.DrawText(percent,&rectClient,DT_VCENTER|DT_CENTER|DT_SINGLELINE);
}
// Do not call CProgressCtrl::OnPaint() for painting messages
}
int CScaleProgressCtrl::SetPos(int nPos)
{
//Set the Position of the Progress
m_nCurrentPosition=nPos;
return (CProgressCtrl::SetPos(nPos));
}
int CScaleProgressCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CProgressCtrl::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
return 0;
}
BOOL CScaleProgressCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
// TODO: 在此添加专用代码和/或调用基类
return CProgressCtrl::Create(dwStyle, rect, pParentWnd, nID);
}
BOOL CScaleProgressCtrl::CreateEx(DWORD dwExStyle, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
// TODO: 在此添加专用代码和/或调用基类
return CProgressCtrl::CreateEx(dwExStyle, dwStyle, rect, pParentWnd, nID);
}
BOOL CScaleProgressCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此添加专用代码和/或调用基类
return CProgressCtrl::PreCreateWindow(cs);
}
void CScaleProgressCtrl::PreSubclassWindow()
{
// TODO: 在此添加专用代码和/或调用基类
CProgressCtrl::PreSubclassWindow();
}
void CScaleProgressCtrl::SetShowScale(BOOL scaleline,int side,int scalenumber)
{
assert(scaleline==0||scaleline==1);
m_ScaleLine=scaleline;
assert(scalenumber>2 && scalenumber<m_nUpper);
m_ScaleNumber=scalenumber;
assert(side<3 && side>=0);
m_Side=side;
return;
}