Qt编写自定义控件:进度按钮

代码:

#ifndef PROGRESSBUTTONWIDGET_H
#define PROGRESSBUTTONWIDGET_H

#include <QWidget>
#include <QTimer>

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 <QPainter>
#include <QPaintEvent>
#include <QPainterPath>
#include <QVariantAnimation>
#include <QDebug>

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<int>(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<QEasingCurve::Type>(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 <QApplication>
#include <QHBoxLayout>

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点击按钮圆形进度打钩效果 

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值