带动画的开关按钮

如下:

绘制步骤:

1、先绘制背景的圆角矩形

2、再根据滑块当前的位置绘制滑块 

3、再绘制文字

4、重写鼠标点击事件,点击后修改开关状态,同时开始属性动画,会不停的修改滑块的当前位置然后重绘

5、重写resize事件,更新滑块的当前位置和属性动画,否则滑块的位置在resize后不会准确

.h文件

#ifndef SWICTCHBUTTON_H
#define SWICTCHBUTTON_H

#include <QWidget>
#include<QPainter>
#include<QBrush>
#include<QMouseEvent>
#include<QPropertyAnimation>

class SwictchButton : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(bool state READ state WRITE setState NOTIFY stateChanged FINAL)
    Q_PROPERTY(int currentX READ currentX WRITE setCurrentX NOTIFY currentXChanged FINAL)
public:
    explicit SwictchButton(QWidget *parent = nullptr);

    bool state() const;
    void setState(bool newState);

    int currentX() const;
    void setCurrentX(int newCurrentX);

protected:
    void paintEvent(QPaintEvent* ev) override;

    void mousePressEvent(QMouseEvent* ev) override;

    void resizeEvent(QResizeEvent* ev) override;

signals:

    void stateChanged();

    void currentXChanged();

private:
    bool mState=false;//默认为关

    QBrush mOffBgColor=Qt::black;//关闭时的背景颜色
    QBrush mOnBgColor=Qt::blue;//开启时的背景颜色

    QBrush mOffIndicatorColor=Qt::red;
    QBrush mOnIndicatorColor=Qt::green;

    QString mOffTxt="OFF";
    QString mOnText="ON";

    int mCurrentX=0;

    QPropertyAnimation* animation;

};

#endif // SWICTCHBUTTON_H

.cpp文件

#include "swictchbutton.h"

SwictchButton::SwictchButton(QWidget *parent)
    : QWidget{parent}
{
    animation=new QPropertyAnimation(this);
    animation->setTargetObject(this);
    animation->setPropertyName("currentX");
    animation->setDuration(300);//开关动画


}

void SwictchButton::paintEvent(QPaintEvent *ev)
{
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing);
    painter.translate(this->rect().center());


    //1、先绘制背景的圆角矩形
    painter.save();
    painter.setPen(Qt::NoPen);
    painter.setBrush(mState?mOnBgColor:mOffBgColor);
    painter.drawRoundedRect(QRect(QPoint(-width()/2,-height()/2),QPoint(width()/2,height()/2)),
                            height()/2,height()/2);
    painter.restore();

    //2、再绘制滑块
    painter.save();
    painter.setPen(Qt::NoPen);
    painter.setBrush(mState?mOnIndicatorColor:mOffIndicatorColor);
    //圆心
    QPoint p(mCurrentX,0);
    painter.drawEllipse(p,height()/2*9/10,height()/2*9/10);
    painter.restore();

    //3、在绘制文字
    painter.save();
    painter.setPen(Qt::white);
    painter.setFont(QFont("宋体",std::min(width(),height())/3));
    painter.drawText(QRect(QPoint(-width()/2,-height()/2),QPoint(width()/2,height()/2)),
                     Qt::AlignCenter,mState?mOnText:mOffTxt);
    painter.restore();


}

//鼠标点击左键,改变状态刷新
void SwictchButton::mousePressEvent(QMouseEvent *ev)
{
    if(animation->state()==QPropertyAnimation::Running)
    {
        return;
    }

    if(ev->button()==Qt::LeftButton)
    {
        //再设置动画的初值和结束值之后  可以改变动画的方向  是前向动画还是回退动画
        mState?animation->setDirection(QVariantAnimation::Backward)
               :animation->setDirection(QVariantAnimation::Forward);
        mState=!mState;
        animation->start();
        emit stateChanged();
    }
}

//每次更新尺寸时就需要修改动画执行的开始位置和结束位置,同时还需要更新滑块的当前位置
void SwictchButton::resizeEvent(QResizeEvent *ev)
{
    mState?mCurrentX=width()/2-height()/2:mCurrentX=-width()/2+height()/2;
    animation->setStartValue(-width()/2+height()/2);
    animation->setEndValue(width()/2-height()/2);
}

int SwictchButton::currentX() const
{
    return mCurrentX;
}

void SwictchButton::setCurrentX(int newCurrentX)
{
    if (mCurrentX == newCurrentX)
        return;
    mCurrentX = newCurrentX;
    update();
}

bool SwictchButton::state() const
{
    return mState;
}

void SwictchButton::setState(bool newState)
{
    if (mState == newState)
        return;
    mState?animation->setDirection(QVariantAnimation::Backward)
           :animation->setDirection(QVariantAnimation::Forward);
    mState = newState;
    emit stateChanged();
    animation->start();
}

知识点:

属性动画的执行方向

QPropertyAnimation::setDirection()

  • QAbstractAnimation::Forward,正向
  • QAbstractAnimation::Backward,反向

我们只需要设置好动画的开始值和结束值,然后执行的时候选择正向还是反向就行了,不需要重新设置开始值和结束值

 mState?animation->setDirection(QVariantAnimation::Backward)
           :animation->setDirection(QVariantAnimation::Forward);
 mState = newState;
 animation->start();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值