Qt 之自定义控件(开关按钮)

发布于:2024-10-13 ⋅ 阅读:(7) ⋅ 点赞:(0)

参考:

1、c++ - Toggle Switch in Qt - Stack Overflow

2、QT中的动画类(QPropertyAnimation)-CSDN博客

利用动画类QPropertyAnimation,点击按钮时,背景色和圆形按钮在一定时间内移动到对面

 _background = new SwitchBackground(this, _oncolor);
    _labelon = new QLabel(this);
    _circle = new SwitchCircle(this, _offcolor);
    __btn_move = new QPropertyAnimation(this);
    __back_move = new QPropertyAnimation(this);

    __btn_move->setTargetObject(_circle);
    __btn_move->setPropertyName("pos");//位置属性,圆形按钮,移动
    __back_move->setTargetObject(_background);
    __back_move->setPropertyName("size");//大小属性,圆角矩形,改变长度

在鼠标点击时间中,根据当前按钮的状态,true是打开,false是关闭,改变动画移动的方向,并且改变背景颜色,已经圆形按钮的颜色

注意圆形按钮和背景色控件的初始大小一样

void SwitchButton::mousePressEvent(QMouseEvent*)//鼠标点击事件
{
    if (!_enabled)
        return;

    __btn_move->stop();
    __back_move->stop();

    __btn_move->setDuration(_duration);//设置持续时间,一般是1000ms
    __back_move->setDuration(_duration);

    int hback = 20;
    QSize initial_size(hback, hback);
    QSize final_size(width() - 4, hback);

    int xi = 2;
    int y  = 2;
    int xf = width() - 22;

    if (_value)//当前点击状态,打开还是关闭,向右移动还是向左移动
    {
        final_size = QSize(hback, hback);
        initial_size = QSize(width() - 4, hback);

        xi = xf;
        xf = 2;
    }

    __btn_move->setStartValue(QPoint(xi, y));
    __btn_move->setEndValue(QPoint(xf, y));

    __back_move->setStartValue(initial_size);
    __back_move->setEndValue(final_size);

    __btn_move->start();
    __back_move->start();

    // Assigning new current value
    _value = !_value;
    emit valueChanged(_value);//发送当前状态,true是打开,false是关闭
}

void SwitchButton::setEnabled(bool flag)
{
    _enabled = flag;
    _circle->setEnabled(flag);
    _background->setEnabled(flag);
    if (flag)
        _labelon->show();
    else
    {
        if (value())
            _labelon->show();
        else
            _labelon->hide();
    }
    QWidget::setEnabled(flag);
}

完整的.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtWidgets>

class SwitchButton : public QWidget
{
    Q_OBJECT
    Q_DISABLE_COPY(SwitchButton)

public:
    enum Style
    {
        YESNO,
        ONOFF,
        BOOL,
        EMPTY
    };

public:
    explicit SwitchButton(QWidget* parent = nullptr, Style style = Style::ONOFF);
    ~SwitchButton() override;

    //-- QWidget methods
    void mousePressEvent(QMouseEvent *) override;
    void paintEvent(QPaintEvent* event) override;
    void setEnabled(bool);

    //-- Setters
    void setDuration(int);
    void setValue(bool);

    //-- Getters
    bool value() const;

signals:
    void valueChanged(bool newvalue);

private:
    class SwitchCircle;
    class SwitchBackground;
    void _update();

private:
    bool _value;
    int  _duration;

    QLinearGradient _lg;
    QLinearGradient _lg2;
    QLinearGradient _lg_disabled;

    QColor _pencolor;
    QColor _offcolor;
    QColor _oncolor;
    int    _tol;
    int    _borderradius;

    // This order for definition is important (these widgets overlap)
    QLabel*           _labeloff;
    SwitchBackground* _background;
    QLabel*           _labelon;
    SwitchCircle*     _circle;

    bool _enabled;

    QPropertyAnimation* __btn_move;
    QPropertyAnimation* __back_move;
};

class SwitchButton::SwitchBackground : public QWidget
{
    Q_OBJECT
    Q_DISABLE_COPY(SwitchBackground)

public:
    explicit SwitchBackground(QWidget* parent = nullptr, QColor color = QColor(154, 205, 50), bool rect = false);
    ~SwitchBackground() override;

    //-- QWidget methods
    void paintEvent(QPaintEvent* event) override;
    void setEnabled(bool);

private:
    bool            _rect;
    int             _borderradius;
    QColor          _color;
    QColor          _pencolor;
    QLinearGradient _lg;
    QLinearGradient _lg_disabled;

    bool _enabled;
};


class SwitchButton::SwitchCircle : public QWidget
{
    Q_OBJECT
    Q_DISABLE_COPY(SwitchCircle)

public:
    explicit SwitchCircle(QWidget* parent = nullptr, QColor color = QColor(255, 255, 255), bool rect = false);
    ~SwitchCircle() override;

    //-- QWidget methods
    void paintEvent(QPaintEvent* event) override;
    void setEnabled(bool);

private:
    bool            _rect;
    int             _borderradius;
    QColor          _color;
    QColor          _pencolor;
    QRadialGradient _rg;
    QLinearGradient _lg;
    QLinearGradient _lg_disabled;

    bool _enabled;
};
#endif // MAINWINDOW_H

.cpp

#include "mainwindow.h"

SwitchButton::SwitchButton(QWidget* parent, Style style)
    : QWidget(parent)
    , _value(false)
    , _duration(100)
    , _enabled(true)
{
    _pencolor = QColor(120, 120, 120);

    _lg = QLinearGradient(35, 30, 35, 0);
    _lg.setColorAt(0, QColor(210, 210, 210));
    _lg.setColorAt(0.25, QColor(255, 255, 255));
    _lg.setColorAt(0.82, QColor(255, 255, 255));
    _lg.setColorAt(1, QColor(210, 210, 210));//QColor(210, 210, 210)

    _lg2 = QLinearGradient(50, 30, 35, 0);
    _lg2.setColorAt(0, QColor(230, 230, 230));
    _lg2.setColorAt(0.25, QColor(255, 255, 255));
    _lg2.setColorAt(0.82, QColor(255, 255, 255));
    _lg2.setColorAt(1, QColor(230, 230, 230));

    _lg_disabled = QLinearGradient(50, 30, 35, 0);
    _lg_disabled.setColorAt(0, QColor(200, 200, 200));
    _lg_disabled.setColorAt(0.25, QColor(230, 230, 230));
    _lg_disabled.setColorAt(0.82, QColor(230, 230, 230));
    _lg_disabled.setColorAt(1, QColor(200, 200, 200));

    _offcolor = QColor(255, 255, 255);
    _oncolor = QColor(154, 205, 50);
    _tol = 0;
    _borderradius = 12;
    _labeloff = new QLabel(this);
    _background = new SwitchBackground(this, _oncolor);
    _labelon = new QLabel(this);
    _circle = new SwitchCircle(this, _offcolor);
    __btn_move = new QPropertyAnimation(this);
    __back_move = new QPropertyAnimation(this);

    __btn_move->setTargetObject(_circle);
    __btn_move->setPropertyName("pos");
    __back_move->setTargetObject(_background);
    __back_move->setPropertyName("size");

    setWindowFlags(Qt::FramelessWindowHint);
    setAttribute(Qt::WA_TranslucentBackground);

    _labeloff->setText("Off");
    _labelon->setText("On");
    _labeloff->move(31, 5);
    _labelon->move(15, 5);
    setFixedSize(QSize(60, 24));
    if (style == Style::YESNO)
    {
        _labeloff->setText("No");
        _labelon->setText("Yes");
        _labeloff->move(33, 5);
        _labelon->move(12, 5);
        setFixedSize(QSize(60, 24));
    }
    else if (style == Style::BOOL)
    {
        _labeloff->setText("False");
        _labelon->setText("True");
        _labeloff->move(37, 5);
        _labelon->move(12, 5);
        setFixedSize(QSize(75, 24));
    }
    if (style == Style::EMPTY)
    {
        _labeloff->setText("");
        _labelon->setText("");
        _labeloff->move(31, 5);
        _labelon->move(12, 5);
        setFixedSize(QSize(45, 24));
    }

    _labeloff->setStyleSheet("color: rgb(120, 120, 120); font-weight: bold;");
    _labelon->setStyleSheet("color: rgb(255, 255, 255); font-weight: bold;");

    _background->resize(20, 20);
//
    _background->move(2, 2);
    _circle->move(2, 2);
}

SwitchButton::~SwitchButton()
{
    delete _circle;
    delete _background;
    delete _labeloff;
    delete _labelon;
    delete __btn_move;
    delete __back_move;
}

void SwitchButton::paintEvent(QPaintEvent*)
{
    QPainter* painter = new QPainter;
    painter->begin(this);
    painter->setRenderHint(QPainter::Antialiasing, true);

    QPen pen(Qt::NoPen);
    painter->setPen(pen);

    painter->setBrush(_pencolor);
    painter->drawRoundedRect(0, 0
                             , width(), height()
                             , 12, 12);

    painter->setBrush(_lg);
    painter->drawRoundedRect(1, 1
                             , width() - 2, height() - 2
                             , 10, 10);

    painter->setBrush(QColor(210, 210, 210));
    painter->drawRoundedRect(2, 2
                             , width() - 4, height() - 4
                             , 10, 10);

    if (_enabled)
    {
        painter->setBrush(_lg2);
        painter->drawRoundedRect(3, 3
                                 , width() - 6, height() - 6
                                 , 7, 7);
    }
    else
    {
        painter->setBrush(_lg_disabled);
        painter->drawRoundedRect(3, 3
                                 , width() - 6, height() - 6
                                 , 7, 7);
    }
    painter->end();
}

void SwitchButton::mousePressEvent(QMouseEvent*)
{
    if (!_enabled)
        return;

    __btn_move->stop();
    __back_move->stop();

    __btn_move->setDuration(_duration);
    __back_move->setDuration(_duration);

    int hback = 20;
    QSize initial_size(hback, hback);
    QSize final_size(width() - 4, hback);

    int xi = 2;
    int y  = 2;
    int xf = width() - 22;

    if (_value)
    {
        final_size = QSize(hback, hback);
        initial_size = QSize(width() - 4, hback);

        xi = xf;
        xf = 2;
    }

    __btn_move->setStartValue(QPoint(xi, y));
    __btn_move->setEndValue(QPoint(xf, y));

    __back_move->setStartValue(initial_size);
    __back_move->setEndValue(final_size);

    __btn_move->start();
    __back_move->start();

    // Assigning new current value
    _value = !_value;
    emit valueChanged(_value);
}

void SwitchButton::setEnabled(bool flag)
{
    _enabled = flag;
    _circle->setEnabled(flag);
    _background->setEnabled(flag);
    if (flag)
        _labelon->show();
    else
    {
        if (value())
            _labelon->show();
        else
            _labelon->hide();
    }
    QWidget::setEnabled(flag);
}

void SwitchButton::setDuration(int time)
{
    _duration = time;
}

void SwitchButton::setValue(bool flag)
{
    if (flag == value())
        return;
    else
    {
        _value = flag;
        _update();
        setEnabled(_enabled);
    }
}

bool SwitchButton::value() const
{
    return _value;
}

void SwitchButton::_update()
{
    int hback = 20;
    QSize final_size(width() - 4, hback);

    int y = 2;
    int xf = width() - 22;

    if (_value)
    {
        final_size = QSize(hback, hback);
        xf = 2;
    }

    _circle->move(QPoint(xf, y));
    _background->resize(final_size);
}

SwitchButton::SwitchBackground::SwitchBackground(QWidget* parent, QColor color, bool rect)
    : QWidget(parent)
    , _rect(rect)
    , _borderradius(12)
    , _color(color)
    , _pencolor(QColor(170, 170, 170))
{
    setFixedHeight(20);

    _lg = QLinearGradient(0, 25, 70, 0);
    _lg.setColorAt(0, QColor(154, 194, 50));
    _lg.setColorAt(0.25, QColor(154, 210, 50));
    _lg.setColorAt(0.95, QColor(154, 194, 50));

    _lg_disabled = QLinearGradient(0, 25, 70, 0);
    _lg_disabled.setColorAt(0, QColor(190, 190, 190));
    _lg_disabled.setColorAt(0.25, QColor(230, 230, 230));
    _lg_disabled.setColorAt(0.95, QColor(190, 190, 190));

    if (_rect)
        _borderradius = 0;

    _enabled = true;
}
SwitchButton::SwitchBackground::~SwitchBackground()
{
}
void SwitchButton::SwitchBackground::paintEvent(QPaintEvent*)
{
    QPainter* painter = new QPainter;
    painter->begin(this);
    painter->setRenderHint(QPainter::Antialiasing, true);

    QPen pen(Qt::NoPen);
    painter->setPen(pen);
    if (_enabled)
    {
        painter->setBrush(QColor(154, 190, 50));
        painter->drawRoundedRect(0, 0
                                 , width(), height()
                                 , 10, 10);

        painter->setBrush(_lg);
        painter->drawRoundedRect(1, 1, width()-2, height()-2, 8, 8);
    }
    else
    {
        painter->setBrush(QColor(150, 150, 150));
        painter->drawRoundedRect(0, 0
                                 , width(), height()
                                 , 10, 10);

        painter->setBrush(_lg_disabled);
        painter->drawRoundedRect(1, 1, width() - 2, height() - 2, 8, 8);
    }
    painter->end();
}
void SwitchButton::SwitchBackground::setEnabled(bool flag)
{
    _enabled = flag;
}

SwitchButton::SwitchCircle::SwitchCircle(QWidget* parent, QColor color, bool rect)
    : QWidget(parent)
    , _rect(rect)
    , _borderradius(12)
    , _color(color)
    , _pencolor(QColor(120, 120, 120))
{
    setFixedSize(20, 20);

    _rg = QRadialGradient(static_cast<int>(width() / 2), static_cast<int>(height() / 2), 12);
    _rg.setColorAt(0, QColor(255, 255, 255));
    _rg.setColorAt(0.6, QColor(255, 255, 255));
    _rg.setColorAt(1, QColor(205, 205, 205));

    _lg = QLinearGradient(3, 18, 20, 4);
    _lg.setColorAt(0, QColor(255, 255, 255));
    _lg.setColorAt(0.55, QColor(230, 230, 230));
    _lg.setColorAt(0.72, QColor(255, 255, 255));
    _lg.setColorAt(1, QColor(255, 255, 255));

    _lg_disabled = QLinearGradient(3, 18, 20, 4);
    _lg_disabled.setColorAt(0, QColor(230, 230, 230));
    _lg_disabled.setColorAt(0.55, QColor(210, 210, 210));
    _lg_disabled.setColorAt(0.72, QColor(230, 230, 230));
    _lg_disabled.setColorAt(1, QColor(230, 230, 230));

    _enabled = true;
}
SwitchButton::SwitchCircle::~SwitchCircle()
{
}
void SwitchButton::SwitchCircle::paintEvent(QPaintEvent*)
{
    QPainter* painter = new QPainter;
    painter->begin(this);
    painter->setRenderHint(QPainter::Antialiasing, true);

    QPen pen(Qt::NoPen);
    painter->setPen(pen);
    painter->setBrush(_pencolor);

    painter->drawEllipse(0, 0, 20, 20);
    painter->setBrush(_rg);
    painter->drawEllipse(1, 1, 18, 18);

    painter->setBrush(QColor(210, 210, 210));
    painter->drawEllipse(2, 2, 16, 16);

    if (_enabled)
    {
        painter->setBrush(_lg);
        painter->drawEllipse(3, 3, 14, 14);
    }
    else
    {
        painter->setBrush(_lg_disabled);
        painter->drawEllipse(3, 3, 14, 14);
    }

    painter->end();
}
void SwitchButton::SwitchCircle::setEnabled(bool flag)
{
    _enabled = flag;
}