Qwidget很强大可以重写任何东西。不信我会让你相信。
话不多说来张图片大家就知道了:

心动吗?我们一起来看看。
首先是沙漏进度代码:
#ifndef NPROGRESANDCLOCK_H
#define NPROGRESANDCLOCK_H
#include <QWidget>
#include <QTimer>
#include <QRect>
#include <QPainter>
#include <QPaintEvent>
#include <QSize>
class NProgreSandClock : public QWidget
{
Q_OBJECT
public:
NProgreSandClock(QWidget *parent);
//设置沙漏外壁的宽
void setSandClockWidth(int width);
//设置是否循环旋转
void setLoop(bool isLoop);
//设置沙漏外边的颜色
void setSandClockColor(QColor color);
//设置沙的颜色
void setSandColor(QColor color);
//设置沙漏下去速度(毫秒)
void setSandDownSpeed(int mes);
//设置沙漏旋转的速度(毫秒)
void setSandClockRoteSpeed(int mes);
//设置当前进度
void setSandClockProgre(int progre);
~NProgreSandClock();
protected:
//重绘事件
void paintEvent(QPaintEvent *);
private:
int m_nNowProgres;
//设置沙漏外壁的宽
int m_nSandClockWidth;
//沙漏旋转的速度
int m_nSandColorRoteSpeed;
//设置沙落下的速度
int m_nSandDowSpeed;
//沙的颜色
QColor m_SandColor;
//沙漏颜色
QColor m_sandClockColor;
//画沙漏
void drawSandClock(QPainter* painter);
bool isLoop;
//旋转沙漏定时器
QTimer* m_updateTimer;//定时器时间
bool isFirstRotate;
//旋转角度
qreal m_angle;
//外半径
qreal m_outerRadius;
//记录现在的状态
int m_nNowStatus;
//是否在画三角形
bool isDrawTri;
//记录三角形的高
qreal triHeight;
//现在的状态
enum
{
DRAW_UP_TRIANG=0,DRAW_DOWN_TRIANG,DRAW_CIR_ROTETE
};
signals:
void onProgres(int);
private slots:
//自定义槽,更新角度旋转
void UpdateAngle();
};
#endif // NPROGRESANDCLOCK_H
沙漏进度CPP:
#include "NProgreSandClock.h"
NProgreSandClock::NProgreSandClock(QWidget *parent)
: QWidget(parent)
,m_nNowStatus(2)
,isLoop(true),
m_angle(0),
m_outerRadius(0),
isDrawTri(false)
,m_sandClockColor(QColor(63,107,157,255))
,m_SandColor(QColor(224,143,36,255))
,m_nSandDowSpeed(5)
,m_nSandColorRoteSpeed(2)
,m_nSandClockWidth(4)
{
//无窗体
setWindowFlags(Qt::FramelessWindowHint);
//背景透明
setAttribute(Qt::WA_TranslucentBackground);
m_updateTimer = new QTimer(this);
//间隔,微妙微单位,大家可以改一下这个值看看转动速度。
m_updateTimer->setInterval(m_nSandColorRoteSpeed);
connect(m_updateTimer,SIGNAL(timeout()),this,SLOT(UpdateAngle()));
//启动定时器
m_updateTimer->start();
}
//重绘事件
void NProgreSandClock::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing|QPainter::HighQualityAntialiasing);//设置反锯齿
drawSandClock(&painter);//画沙漏
}
//画沙漏和三角形
void NProgreSandClock::drawSandClock(QPainter *painter)
{
m_outerRadius = width() > height() ? (qreal)height()/2 : (qreal)width()/2;
if (m_nNowStatus== DRAW_CIR_ROTETE)
{
triHeight=m_outerRadius;
}
painter->save();
// move to center
painter->translate(m_outerRadius,m_outerRadius);
painter->setPen(QPen(m_sandClockColor,m_nSandClockWidth,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin));
//旋转
painter->rotate(m_angle);
QRect widgetRect =this->rect();
QPainterPath sandClockPath;
sandClockPath.moveTo(-m_outerRadius*0.05,m_outerRadius*0.05);
sandClockPath.lineTo(m_outerRadius*0.1,m_outerRadius);
sandClockPath.lineTo(m_outerRadius,m_outerRadius*0.1);
sandClockPath.lineTo(m_outerRadius*0.05,-m_outerRadius*0.05);
sandClockPath.lineTo(-m_outerRadius*0.1,-m_outerRadius);
sandClockPath.lineTo(-m_outerRadius,-m_outerRadius*0.1);
sandClockPath.lineTo(-m_outerRadius*0.05,m_outerRadius*0.05);
painter->drawPath(sandClockPath);
painter->setPen(Qt::NoPen);
if (isLoop)
{
emit onProgres(-1);
QPoint triangle[3];
painter->setBrush(QBrush(m_SandColor,Qt::SolidPattern));//设置画刷形式
if (m_nNowStatus==DRAW_UP_TRIANG)
{
if (isDrawTri)
{
triangle[0]=QPoint(0,0);
triangle[1]=QPoint(-triHeight*0.1,-triHeight);
triangle[2]=QPoint(-triHeight,-triHeight*0.1);
triHeight-=1;
painter->drawPolygon(triangle,3);
triangle[0]=QPoint(0,0);
triangle[1]=QPoint((m_outerRadius*0.1)-triHeight*0.1,m_outerRadius-triHeight);
triangle[2]=QPoint(m_outerRadius-triHeight,(m_outerRadius*0.1)-triHeight*0.1);
if (triHeight<0)
{
isDrawTri=false;
triHeight=m_outerRadius;
m_nNowStatus= DRAW_CIR_ROTETE;
m_angle+=1;
}
painter->drawPolygon(triangle,3);
}
}
else if(m_nNowStatus==DRAW_DOWN_TRIANG)
{
if (isDrawTri)
{
triangle[0]=QPoint(0,0);
triangle[1]=QPoint(triHeight*0.1,triHeight);
triangle[2]=QPoint(triHeight,triHeight*0.1);
triHeight-=1;
painter->drawPolygon(triangle,3);
triangle[0]=QPoint(0,0);
triangle[1]=QPoint(-(m_outerRadius*0.1)+triHeight*0.1,-m_outerRadius+triHeight);
triangle[2]=QPoint(-m_outerRadius+triHeight,-(m_outerRadius*0.1)+triHeight*0.1);
if (triHeight<=0)
{
isDrawTri=false;
triHeight=m_outerRadius;
m_nNowStatus= DRAW_CIR_ROTETE;
m_angle+=1;
}
painter->drawPolygon(triangle,3);
}
}
else
{
if(m_angle>45&&m_angle<=225)
{
triangle[0]=QPoint(0,0);
triangle[1]=QPoint(m_outerRadius*0.1-m_nSandClockWidth/3,m_outerRadius-m_nSandClockWidth/3);
triangle[2]=QPoint(m_outerRadius-m_nSandClockWidth/3,m_outerRadius*0.1-m_nSandClockWidth/3);
}
else
{
triangle[0]=QPoint(0,0);
triangle[1]=QPoint(-m_outerRadius*0.1+m_nSandClockWidth/3,-m_outerRadius+m_nSandClockWidth/3);
triangle[2]=QPoint(-m_outerRadius+m_nSandClockWidth/3,-m_outerRadius*0.1+m_nSandClockWidth/3);
}
painter->drawPolygon(triangle,3);
}
}
else
{
qreal nTriHeight=((float)(m_nNowProgres/100.0)*triHeight);
emit onProgres(m_nNowProgres);
painter->setBrush(QBrush(m_SandColor,Qt::SolidPattern));//设置画刷形式
QPoint triangle[3];
triangle[0]=QPoint(0,0);
triangle[1]=QPoint(nTriHeight*0.1,nTriHeight);
triangle[2]=QPoint(nTriHeight,nTriHeight*0.1);
painter->drawPolygon(triangle,3);
triangle[0]=QPoint(0,0);
triangle[1]=QPoint(-(m_outerRadius*0.1)+nTriHeight*0.1,-m_outerRadius+nTriHeight);
triangle[2]=QPoint(-m_outerRadius+nTriHeight,-(m_outerRadius*0.1)+nTriHeight*0.1);
painter->drawPolygon(triangle,3);
}
painter->restore();
}
//更新画面
void NProgreSandClock::UpdateAngle()
{
if ((m_angle==45) )
{
m_nNowStatus=DRAW_UP_TRIANG;
m_updateTimer->start(m_nSandDowSpeed);
isDrawTri=true;
}
else if (m_angle==225)
{
m_nNowStatus=DRAW_DOWN_TRIANG;
m_updateTimer->start(m_nSandDowSpeed);
isDrawTri=true;
}
else
{
m_nNowStatus= DRAW_CIR_ROTETE;
m_updateTimer->setInterval(m_nSandColorRoteSpeed);
}
if (!isDrawTri)
{
m_angle += 1;
if(m_angle > 360)
{
m_angle = 0;
}
}
//刷新控件,会调用paintEvent函数
update();
}
NProgreSandClock::~NProgreSandClock()
{
m_updateTimer->stop();
}
//设置是否循环
void NProgreSandClock::setLoop(bool isLoop)
{
this->isLoop=isLoop;
}
//设置沙漏颜色
void NProgreSandClock::setSandClockColor(QColor color)
{
this->m_sandClockColor= color;
}
//设置沙的颜色
void NProgreSandClock::setSandColor(QColor color)
{
this->m_SandColor = color;
}
//设置沙下降的速度
void NProgreSandClock::setSandDownSpeed(int mes)
{
this->m_nSandDowSpeed=mes;
}
//设置沙漏旋转的速度
void NProgreSandClock::setSandClockRoteSpeed(int mes)
{
this->m_nSandColorRoteSpeed= mes;
}
//设置沙漏的宽度
void NProgreSandClock::setSandClockWidth(int width)
{
this->m_nSandClockWidth=width;
}
//设置当前进度
void NProgreSandClock::setSandClockProgre(int progre)
{
this->m_nNowProgres = progre;
if (progre>100)
{
this->m_nNowProgres=100;
}
m_angle = 45;
m_updateTimer->stop();
isLoop = false;
update();
}
首先沙漏进度还是很简单的:那么再来看看水波进度:
#ifndef NPROGRECIRWATER_H
#define NPROGRECIRWATER_H
#define WATER_HEIGHT 0.06
#include <QWidget>
#include <math.h>
#include <QPainter>
#include <QPixmap>
#include <QTimer>
#include <QFont>
class NProgreCirWater : public QWidget
{
Q_OBJECT
public:
NProgreCirWater(QWidget *parent);
~NProgreCirWater();
void setWaterProgre(int progre);
protected:
void paintEvent(QPaintEvent *event);
private:
int m_nNowProgre;
QTimer m_ChangeWaterTimer;
float m_fPy;
void createShader(QPainter &painter);
QTimer m_TUpGuiimer;
// 水波进度
float DEFAULT_LEVEL_RATIO ;
// 水波高度
float DEFAULT_AMPLITUDE_RATIO ;
private slots:
//自动增加
void upAutoTime();
//让波浪动起来
void upGuiOutTimer();
};
#endif // NPROGRECIRWATER_H
再来看看实现代码CPP:
#include "NProgreCirWater.h"
#include "QTool.h"
#define M_PI 3.14159265358979323846
NProgreCirWater::NProgreCirWater(QWidget *parent)
: QWidget(parent),m_fPy(0)
{
// 水波进度
DEFAULT_LEVEL_RATIO = 1.0f;
// 水波高度
DEFAULT_AMPLITUDE_RATIO = 0;
connect(&m_ChangeWaterTimer,SIGNAL(timeout()),this,SLOT(upAutoTime()));
connect(&m_TUpGuiimer,SIGNAL(timeout()),this,SLOT(upGuiOutTimer()));
m_TUpGuiimer.start(10);
m_ChangeWaterTimer.start(90);
}
NProgreCirWater::~NProgreCirWater()
{
}
void NProgreCirWater::createShader(QPainter &painter) {
painter.setRenderHints(QPainter::Antialiasing|QPainter::HighQualityAntialiasing);//设置反锯齿
int height = this-> height();
int width = this->width();
// ω周期 让一个周期的宽度正好是width
double frequency = 3 * M_PI / width;
// A振幅 默认的振幅是高度的0.05f
float amplitude = height * DEFAULT_AMPLITUDE_RATIO;
// k(y轴偏移量,进度) 默认的进度是50%
float level = height * DEFAULT_LEVEL_RATIO;
QPixmap waveBitmap (width,height);
QPainter drawWaterPainter(&waveBitmap);
drawWaterPainter.setPen(Qt::NoPen);
drawWaterPainter.setBrush(Qt::red);
QPainterPath abovePath ;
QPainterPath behindPath ;
abovePath.moveTo(0, height);
behindPath.moveTo(0, height);
m_fPy+=0.05;
if (m_fPy>(width/2))
{
m_fPy = 0;
}
for(int x = 0; x<=width; x++) {
// y=Asin(ωx+φ)+k
float aboveY = (float) (amplitude * sin(frequency * x+m_fPy))+ level;
// 背面的水波偏移一些,和前面的错开。
float behindY = (float) (amplitude * sin(frequency * x+width/4*frequency+m_fPy ))+ level;
abovePath.lineTo(x , aboveY);
behindPath.lineTo(x, behindY);
}
abovePath.lineTo(width+ 1, height);
behindPath.lineTo(width+1, height);
drawWaterPainter.setBrush(QColor(169,245,233,255));
drawWaterPainter.drawPath(behindPath);
drawWaterPainter.setBrush(QColor(40,230,200,255));
drawWaterPainter.drawPath(abovePath);
int nFontSize = width/6;
QFont font;
font.setPixelSize(nFontSize);
drawWaterPainter.setFont(font);
drawWaterPainter.setPen(QPen(Qt::white));
int nNowPro =100 - (int)(DEFAULT_LEVEL_RATIO*100);
QString strProgre = QString::number(nNowPro);
strProgre.append("%");
drawWaterPainter.drawText(width/2-(nFontSize/2-2),height/2+nFontSize/2,strProgre);
drawWaterPainter.end();
waveBitmap=QTool::QPixmapToRound(waveBitmap,(float)100);
painter.drawPixmap(0,0,waveBitmap);
}
//重绘事件
void NProgreCirWater::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
createShader(painter);
QWidget::paintEvent(event);
}
void NProgreCirWater::upGuiOutTimer()
{
update();
}
void NProgreCirWater::upAutoTime()
{
// 水波高度
if (DEFAULT_LEVEL_RATIO<=0)
{
DEFAULT_LEVEL_RATIO=1;
DEFAULT_AMPLITUDE_RATIO=0;
}
DEFAULT_LEVEL_RATIO-=0.01;
DEFAULT_AMPLITUDE_RATIO= (1-DEFAULT_LEVEL_RATIO) * 0.15;
if (DEFAULT_AMPLITUDE_RATIO>WATER_HEIGHT)
{
DEFAULT_AMPLITUDE_RATIO =WATER_HEIGHT;
}
}
void NProgreCirWater::setWaterProgre(int progre)
{
this->m_nNowProgre = progre;
m_ChangeWaterTimer.stop();
DEFAULT_LEVEL_RATIO =1.0 - ((float)this->m_nNowProgre) /100.0;
DEFAULT_AMPLITUDE_RATIO= (1-DEFAULT_LEVEL_RATIO) * 0.15;
if (DEFAULT_AMPLITUDE_RATIO>WATER_HEIGHT)
{
DEFAULT_AMPLITUDE_RATIO =WATER_HEIGHT;
}
update();
}
下面是调用代码:
resize(800,800);
NImageButton *pNImageButton = new NImageButton(this);
pNImageButton->setGeometry(10,10,120,35);
pNImageButton->setMinimumSize(120,35);
QPixmap pp("Image/button.png");
QPixmap ppc("Image/button1.png");
pNImageButton->setNormalImage(pp);
pNImageButton->setPressImage(ppc);
pNImageButton->setImageArc(10);
NProgreCirWater *pNCirProgreWater=new NProgreCirWater(this);
pNCirProgreWater->setWaterProgre(35);
pNCirProgreWater->setGeometry(110,10,200,200);
pNCirProgreWater->setMinimumSize(200,200);
NProgreCirWater *pNCirProgreWater1=new NProgreCirWater(this);
//pNCirProgreWater1->setWaterProgre(35);
pNCirProgreWater1->setGeometry(330,10,200,200);
pNCirProgreWater1->setMinimumSize(200,200);
NProgreSandClock * pCirProgreWater=new NProgreSandClock(this);
pCirProgreWater->setSandDownSpeed(10);
pCirProgreWater->setSandClockProgre(35);
pCirProgreWater->setSandColor(QColor(Qt::red));
pCirProgreWater->setGeometry(110,220,200,100);
pCirProgreWater->setMinimumSize(200,200);
NProgreSandClock * pCirProgreWater1=new NProgreSandClock(this);
pCirProgreWater1->setSandDownSpeed(10);
// pCirProgreWater1->setSandClockProgre(35);
pCirProgreWater1->setSandColor(QColor(Qt::red));
pCirProgreWater1->setGeometry(330,220,100,100);
pCirProgreWater1->setMinimumSize(200,200);
好了还是那句老话,学如逆水行舟不进则退。