代码:
#ifndef PROGRESSBUTTONWIDGET_H
#define PROGRESSBUTTONWIDGET_H
#include
#include
class progressButtonWidget : public QWidget
{
Q_OBJECT
public:
progressButtonWidget(QWidget *parent = nullptr);
~progressButtonWidget();
signals:
void startProcessing();
protected:
void paintEvent(QPaintEvent *event)override;
void enterEvent(QEnterEvent *event)override;
void leaveEvent(QEvent *event)override;
void mousePressEvent(QMouseEvent *event)override;
private:
enum class state
{
normal,
hover,
fromRoundedCornersToRounded,//从圆角变成圆形
openProgress,
closeProgress,
recovery
}
buttonState{state::normal};
QString text{"我是按钮"};
QTimer timer;
int widthChangeValue{0};
void onTimeout();
void operationProcessing();
int progress{0};//处理百分比
};
class WaterDrop : public QWidget
{
Q_OBJECT
public:
WaterDrop(QWidget *parent = Q_NULLPTR);
void show();
void move(const QPoint &point);
private:
void paintEvent(QPaintEvent *event);
void onRaduisChanged(QVariant value);
private:
class QVariantAnimation* m_waterDropAnimation;
int m_animationRadius;
};
#endif // PROGRESSBUTTONWIDGET_H
#include "progressbuttonwidget.h"
#include
#include
#include
#include
#include
progressButtonWidget::progressButtonWidget(QWidget *parent)
: QWidget(parent)
{
this->setWindowFlags(Qt::FramelessWindowHint);
this->setAttribute(Qt::WA_TranslucentBackground, true);
setFixedHeight(60);
setMinimumWidth(140);
auto font = this->font();
font.setPixelSize(24);
setFont(font);
setMouseTracking(true);
connect(&timer,&QTimer::timeout,this,&progressButtonWidget::onTimeout);
connect(this,&progressButtonWidget::startProcessing,this,&progressButtonWidget::operationProcessing,Qt::QueuedConnection);
timer.setInterval(40);
}
progressButtonWidget::~progressButtonWidget()
{
}
void progressButtonWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing,true);
auto rect = event->rect();
if(buttonState == state::normal || buttonState == state::hover)
{
QPainterPath path;
path.addRoundedRect(rect,30,30);
painter.setClipPath(path);
painter.fillRect(rect,Qt::white);
painter.save();
painter.setBrush(QColor(buttonState == state::normal ? 0x51c582 : 0x37be77));
painter.setPen(Qt::transparent);
painter.drawRoundedRect(rect.adjusted(3,3,-3,-3),30,30);
painter.restore();
painter.setPen(Qt::white);
painter.setFont(this->font());
painter.drawText(rect, Qt::AlignCenter, text);
}
else if(buttonState == state::fromRoundedCornersToRounded || buttonState == state::recovery)
{
painter.setBrush(QColor(0x51c582));
painter.setPen(QPen(QColor(0x45B078),3));
painter.translate(rect.center());
painter.drawRoundedRect(QRect(-widthChangeValue,
-(rect.height() / 2 - 3),
widthChangeValue * 2,
rect.height() - 6),30,30);
}
else if(buttonState == state::openProgress)
{
painter.translate(rect.center());
auto radiu = (rect.height() - 6) / 2 -3;
painter.setBrush(QColor(0x51c582));
painter.setPen(QPen(QColor(0x45B078),3));
painter.drawEllipse(QPoint(0,0),radiu,radiu);
painter.setPen(QPen(Qt::white,3));
QRect rect = QRect(-radiu, -radiu,
radiu*2, radiu*2);
auto angle = progress * 360 / 100;
painter.drawArc(rect.adjusted(-3,-3,3,3),90 * 16,-static_cast(angle * 16));
}
else if(buttonState == state::closeProgress)
{
auto radiu = (rect.height() - 6) / 2;
painter.translate(rect.center());
painter.setPen(Qt::transparent);
painter.setBrush(QColor(0, 0, 0, 63));
painter.drawEllipse(QPoint(0,0),radiu,radiu);
radiu -= 3;
painter.setBrush(Qt::white);
painter.drawEllipse(QPoint(0,0),radiu,radiu);
painter.setPen(QPen(QColor("#4DAF51"),3,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin));
painter.drawLine(QPoint(-radiu / 3,0),
QPoint(-radiu / 5,radiu / 3));
painter.drawLine(QPoint(-radiu / 5,radiu / 3),
QPoint(radiu / 4,-radiu / 4));
}
}
void progressButtonWidget::enterEvent(QEnterEvent *event)
{
if(buttonState == state::normal)
{
buttonState = state::hover;
update();
}
QWidget::enterEvent(event);
}
void progressButtonWidget::leaveEvent(QEvent *event)
{
if(buttonState == state::hover)
{
buttonState = state::normal;
update();
}
QWidget::leaveEvent(event);
}
void progressButtonWidget::mousePressEvent(QMouseEvent *event)
{
if(buttonState == state::hover || buttonState == state::normal)
{
buttonState = state::fromRoundedCornersToRounded;
widthChangeValue = (this->width() - 6) / 2;
timer.start();
update();
}
else if(buttonState == state::closeProgress)
{
buttonState = state::recovery;
timer.start();
update();
}
QWidget::mousePressEvent(event);
}
void progressButtonWidget::onTimeout()
{
if(buttonState == state::fromRoundedCornersToRounded)
{
widthChangeValue -= (this->width() * 0.05);
if(widthChangeValue <= (this->height()))
{
buttonState = state::openProgress;
progress = 0;
timer.stop();
emit startProcessing();
}
}
else
{
widthChangeValue += (this->width() * 0.05);
if(widthChangeValue >= (this->width() / 2))
{
buttonState = state::normal;
timer.stop();
}
}
update();
}
void progressButtonWidget::operationProcessing()
{
for(int i = 0;i < 500000000;++i)
{
if(i % 5000000 == 0)
{
++progress;
repaint();
}
}
if(progress == 100)
{
buttonState = state::closeProgress;
update();
auto waterDrop = new WaterDrop();
waterDrop->move(this->mapToGlobal(this->rect().center()));
waterDrop->show();
}
}
const int RADIUS = 60;
WaterDrop::WaterDrop(QWidget *parent)
: QWidget(parent)
, m_waterDropAnimation(nullptr)
, m_animationRadius(0)
{
this->setFixedSize(QSize(RADIUS * 2, RADIUS * 2));
this->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
this->setAttribute(Qt::WA_TranslucentBackground);
this->setAttribute(Qt::WA_DeleteOnClose);
m_waterDropAnimation = new QVariantAnimation(this);
// m_waterDropAnimation->setEasingCurve(QEasingCurve(static_cast(QRandomGenerator::global()->bounded(40))));
}
//把鼠标点击的点转换为圆心点坐标
void WaterDrop::move(const QPoint &point)
{
QPoint translatePoint = point - QPoint(RADIUS, RADIUS);
QWidget::move(translatePoint);
}
void WaterDrop::show()
{
m_waterDropAnimation->setStartValue(0);
m_waterDropAnimation->setEndValue(RADIUS);
m_waterDropAnimation->setDuration(350);
connect(m_waterDropAnimation, &QVariantAnimation::valueChanged, this, &WaterDrop::onRaduisChanged);
connect(m_waterDropAnimation, &QVariantAnimation::finished, this, &WaterDrop::close);
m_waterDropAnimation->start();
QWidget::show();
}
void WaterDrop::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPen pen;
pen.setColor(QColor(0xffffff80));
pen.setWidth(5);
painter.setPen(pen);
painter.drawEllipse(event->rect().center(),m_animationRadius, m_animationRadius);
}
void WaterDrop::onRaduisChanged(QVariant value)
{
m_animationRadius = value.toInt();
update();
}
使用:
#include "progressbuttonwidget.h"
#include
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.setPalette(QPalette(QPalette::Base,QColor("#128bf1")));
auto btn = new progressButtonWidget;
auto hb = new QHBoxLayout(&w);
hb->setContentsMargins(50,50,50,50);
hb->addWidget(btn);
w.resize(800,800);
w.show();
return a.exec();
}
效果:
UI参考:CSS3点击按钮圆形进度打钩效果