Qt编写自定义控件:彩色渐变圆角按钮之一

代码:

#ifndef COLORGRADIENTROUNDEDBUTTON_H
#define COLORGRADIENTROUNDEDBUTTON_H

#include <QAbstractButton>

struct doubleColor
{
    doubleColor(QColor frist = Qt::red,QColor second = Qt::blue)
        :fristColor(frist),secondColor(second)
    {}
    QColor fristColor;
    QColor secondColor;

    bool operator !=(const doubleColor & c)
    {
        return (this->fristColor != c.fristColor) || (this->secondColor != c.secondColor);
    }
};
Q_DECLARE_METATYPE(doubleColor)

class ColorGradientRoundedButton : public QAbstractButton
{
    Q_OBJECT
    Q_PROPERTY(doubleColor currentColor MEMBER currentColor)

public:
    ColorGradientRoundedButton(QWidget *parent = nullptr);
    ~ColorGradientRoundedButton()override;

protected:
    void paintEvent(QPaintEvent *event)override;
    void enterEvent(QEnterEvent *event)override;
    void leaveEvent(QEvent *event)override;

private:
    void onValueChanged(const QVariant &value);
    doubleColor currentColor;
    doubleColor startColor;
    doubleColor endColor;
    class QPropertyAnimation * animation{nullptr};
};
#endif // COLORGRADIENTROUNDEDBUTTON_H
#include "colorgradientroundedbutton.h"
#include <QPainter>
#include <QPaintEvent>
#include <QGraphicsDropShadowEffect>
#include <QPropertyAnimation>
#include <QDebug>
#include <QPainterPath>
#include <QRandomGenerator>

QVariant myColorInterpolator(const doubleColor &start, const doubleColor &end, qreal progress)
{
    auto fr = start.fristColor.red() + ((end.fristColor.red() - start.fristColor.red()) * progress);
    auto fg = start.fristColor.green() + ((end.fristColor.green() - start.fristColor.green()) * progress);
    auto fb = start.fristColor.blue() + ((end.fristColor.blue() - start.fristColor.blue()) * progress);

    auto sr = start.secondColor.red() + ((end.secondColor.red() - start.secondColor.red()) * progress);
    auto sg = start.secondColor.green() + ((end.secondColor.green() - start.secondColor.green()) * progress);
    auto sb = start.secondColor.blue() + ((end.secondColor.blue() - start.secondColor.blue()) * progress);

    return QVariant::fromValue(doubleColor(QColor(fr,fg,fb),QColor(sr,sg,sb)));
}

QColor getRandomColor()
{
    return QColor(QRandomGenerator::global()->bounded(255),
                  QRandomGenerator::global()->bounded(255),
                  QRandomGenerator::global()->bounded(255));
}

ColorGradientRoundedButton::ColorGradientRoundedButton(QWidget *parent)
    : QAbstractButton(parent)
{
    qRegisterAnimationInterpolator<doubleColor>(myColorInterpolator);

    startColor = doubleColor(getRandomColor(),getRandomColor());
    endColor = doubleColor(getRandomColor(),getRandomColor());
    currentColor = startColor;

    this->setMinimumSize(180,50);
    setMouseTracking(true);

    QGraphicsDropShadowEffect * effect = new QGraphicsDropShadowEffect(this);
    setGraphicsEffect(effect);
    effect->setOffset(0,0);
    effect->setBlurRadius(25);
    effect->setColor(Qt::black);

    animation = new QPropertyAnimation(this, "currentColor");
    animation->setDuration(400);
    connect(animation,&QPropertyAnimation::valueChanged,this,&ColorGradientRoundedButton::onValueChanged);
}

ColorGradientRoundedButton::~ColorGradientRoundedButton()
{
}

void ColorGradientRoundedButton::onValueChanged(const QVariant &value)
{
    update();
}

void ColorGradientRoundedButton::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing,true);

    auto rect = event->rect();

    QPainterPath path;
    path.addRoundedRect(rect,25,25);
    painter.setClipPath(path);
    painter.drawRect(rect);

    QLinearGradient linearGradient(rect.topLeft(),rect.topRight());
    linearGradient.setColorAt(0,currentColor.fristColor);
    linearGradient.setColorAt(1,currentColor.secondColor);
    painter.fillRect(rect,linearGradient);

    auto font = painter.font();
    font.setBold(true);
    font.setPixelSize(20);
    painter.setFont(font);
    painter.setPen(Qt::white);
    painter.drawText(rect,Qt::AlignCenter,text());
}

void ColorGradientRoundedButton::enterEvent(QEnterEvent *event)
{
    if(animation->state() == QAbstractAnimation::Running)
    {
        animation->stop();
    }
    animation->setStartValue(QVariant::fromValue(currentColor));
    animation->setEndValue(QVariant::fromValue(endColor));
    animation->start();

    QWidget::enterEvent(event);
}

void ColorGradientRoundedButton::leaveEvent(QEvent *event)
{
    if(animation->state() == QAbstractAnimation::Running)
    {
        animation->stop();
    }
    animation->setStartValue(QVariant::fromValue(currentColor));
    animation->setEndValue(QVariant::fromValue(startColor));
    animation->start();

    QWidget::leaveEvent(event);
}

使用示例:

    QWidget w;
    w.setPalette(Qt::white);
    auto vb = new QVBoxLayout;
    vb->setSpacing(15);
    for(int i = 0;i < 8;++i)
    {
        auto btn = new ColorGradientRoundedButton;
        btn->setText(QString("按钮%1").arg(i));
        vb->addWidget(btn);
    }
    w.setLayout(vb);
    w.show();

效果:

相关博文:Qt动画框架:QVariantAnimation

Guess you like

Origin blog.csdn.net/kenfan1647/article/details/121412140