如下:
绘制步骤:
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();