参考博客地址https://blog.csdn.net/liang19890820/article/details/52164289
大神提供了很好的思路,我在原文章的思路上理解若有不正确的,欢迎指正
基本原理如下:
?绘制滑动开关的原理如下:
??

?SwBtn.h文件代码如下 ——相关注释我都写了自己的理解
#ifndef SWBTN_H
#define SWBTN_H
#include <QWidget>
#include <QTimer>
class SWBtn : public QWidget
{
Q_OBJECT
public:
explicit SWBtn(QWidget *parent = nullptr);
bool SwBtn_isChecked() const; //返回开关状态 打开——true 关闭——false
void setSwBtn_Status(bool check); //设置开关状态
void setSwBtn_BackgroundColor(QColor color); //设置背景颜色
void setSwBtn_CheckedColor(QColor color); //设置选中颜色
void setSwBtn_DisabilityColor(QColor color); //设置不可用的颜色
void setSwBtn_WidgetSize(int m_width,int m_height); //设置整个按键窗口大小
protected:
void paintEvent(QPaintEvent *event) override; //重写绘图事件——绘制按钮
//重写鼠标左键按压事件 Q_DECL_OVERRIDE(这个宏可以用来声明一个覆盖的虚函数) override在这里等于这个宏
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE/*等同于Q_DECL_OVERRIDE*/; //override c++11特性
//切记一定要对虚函数进行重新实现 不然未重新实现虚函数 override会使得报错
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; //重写鼠标释放事件
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; //重写大小变化事件
QSize sizeHint() const Q_DECL_OVERRIDE; //重写返回默认推荐大小
QSize minimumSizeHint() const Q_DECL_OVERRIDE; //重写返回推荐的最小大小
signals:
//当开关状态改变时,发射信号(鼠标释放)
void SwBtn_SWITCH(bool check);
private slots:
void SwBtn_Slide(); //槽函数实现 圆形滑动
private:
bool m_SwBtn_Status; //开关状态
QColor m_SwBtn_background; // 背景颜色
QColor m_SwBtn_checkedColor; // 选中颜色
QColor m_SwBtn_disabilityColor; // 不可用颜色
QColor m_SwBtn_thumbColor; // 小圆圈颜色
qreal m_SwBtn_radius; // 圆角
qreal m_SwBtn_X; // 窗口x点坐标
qreal m_SwBtn_Y; // 窗口y点坐标
qint16 m_SwBtn_Height; // 高度
qint16 m_SwBtn_Margin; // 外边距
QTimer m_SwBtn_timer; // 定时器
};
#endif // SWBTN_H
?SwBtn.cpp文件具体实现如下:相关注释也写好了
/**************头文件******************/
#include "swbtn.h"
#include <QPainter>
#include <QMouseEvent>
/*****************END*****************/
SWBtn::SWBtn(QWidget *parent) : QWidget(parent),
m_SwBtn_Status(false),
m_SwBtn_background(Qt::black),
// m_SwBtn_checkedColor(0,150,136),
m_SwBtn_checkedColor(255,000,000),
m_SwBtn_disabilityColor(190,190,190),
m_SwBtn_thumbColor(Qt::white),
m_SwBtn_radius(12), //半圆半径
m_SwBtn_Height(24), //窗口高度
m_SwBtn_Margin(5) //窗口边距
//切记,以上构造函数要按自己的私有属性中的成员顺序来赋值,不然会报错
{
/*this->*/setCursor(Qt::PointingHandCursor); //设置鼠标光标在小部件上的形状 此处为手型
//QT4 信号与槽实现 此处是时间变化改变转换开关滑动时状态
connect(&m_SwBtn_timer,SIGNAL(timeout()),this,SLOT(SwBtn_Slide()));
}
//返回开关状态
bool SWBtn::SwBtn_isChecked() const
{
return m_SwBtn_Status;
}
//设置开关状态
void SWBtn::setSwBtn_Status(bool check)
{
m_SwBtn_Status=check;
m_SwBtn_timer.start(10);
}
//设置背景颜色
void SWBtn::setSwBtn_BackgroundColor(QColor color)
{
m_SwBtn_background=color;
}
//设置选中颜色
void SWBtn::setSwBtn_CheckedColor(QColor color)
{
m_SwBtn_checkedColor=color;
}
//设置不可用时颜色
void SWBtn::setSwBtn_DisabilityColor(QColor color)
{
m_SwBtn_disabilityColor=color;
}
//设置整个按键窗口宽度和高度
void SWBtn::setSwBtn_WidgetSize(int m_width, int m_height)
{
this->m_SwBtn_Height=m_width-m_height;
this->m_SwBtn_Margin=m_height-(m_width/2);
this->m_SwBtn_radius=m_SwBtn_Height/2;
update();
}
void SWBtn::paintEvent(QPaintEvent *event)
{
/* Q_UNUSED指示编译器没有在函数体中使用指定名称的形参。
* 这可以用来抑制编译器警告,同时允许在函数的签名中定义有意义的参数名。*/
Q_UNUSED(event);
QPainter painter(this);
painter.setPen(Qt::NoPen); //设置画笔
painter.setRenderHint(QPainter::Antialiasing); //设置消除边缘锯齿
QPainterPath path;
QColor background; //背景色
QColor thumbColor; //小圆颜色
qreal pellucidity; //透明度参数 浮点型
if(isEnabled()){ //是否可用状态
if(m_SwBtn_Status){ //打开状态
background=m_SwBtn_checkedColor;
thumbColor=m_SwBtn_checkedColor;
pellucidity=0.6;
}
else{ //关闭状态
background=m_SwBtn_background;
thumbColor=m_SwBtn_thumbColor;
pellucidity=0.8;
}
}
else{ //不可用状态
background=m_SwBtn_background;
thumbColor=m_SwBtn_disabilityColor;
pellucidity=0.2;
}
//绘制背景圆角矩形
painter.setBrush(background); //设置画刷
painter.setOpacity(pellucidity); //设置透明度
//设置圆角矩形参数 QRectF(x,y,长,高) x半径 y半径 (3,3)左上角 矩形(32*16) 半径(8,8)
path.addRoundedRect(QRectF(m_SwBtn_Margin,
m_SwBtn_Margin,
width()-2*m_SwBtn_Margin,
height()-2*m_SwBtn_Margin),
m_SwBtn_radius,
m_SwBtn_radius);
painter.drawPath(path.simplified()); //加载路径
//绘制小圆圈
painter.setBrush(thumbColor);
painter.setOpacity(1);
//绘制矩形中的椭圆 给定一个矩形 返回贴着边的椭圆 (22*22)
// painter.drawEllipse(QRectF(m_SwBtn_X-(m_SwBtn_Height/2),
// m_SwBtn_Y-(m_SwBtn_Height/2),
// height(),
// height()));
painter.drawEllipse(QRectF(m_SwBtn_X/*-(m_SwBtn_Height/2)*/,
m_SwBtn_Y/*-(m_SwBtn_Height/2)*/,
height(),
height()));
}
//鼠标按下事件
void SWBtn::mousePressEvent(QMouseEvent *event)
{
if(isEnabled()){
//判断是否左键安按下
if(event->button()==Qt::LeftButton){ //**
event->accept();
}
else
event->ignore();
}
}
//鼠标释放按键 发射状态改变信号
void SWBtn::mouseReleaseEvent(QMouseEvent *event)
{
if(isEnabled()){
if((event->type()==QMouseEvent::MouseButtonRelease)&&(event->button()==Qt::LeftButton)){
event->accept();
m_SwBtn_Status=!m_SwBtn_Status; //改变当前开关状态
emit SwBtn_SWITCH(m_SwBtn_Status); //发射改变以后的状态
m_SwBtn_timer.start(10); //定时器10ms响应一次
}
else{
event->ignore(); //忽略该事件
}
}
}
//重现大小改变事件
void SWBtn::resizeEvent(QResizeEvent *event)
{
// m_SwBtn_X=m_SwBtn_Height/2; //x=8
// m_SwBtn_Y=m_SwBtn_Height/2; //y=8
m_SwBtn_X=0;
m_SwBtn_Y=0;
QWidget::resizeEvent(event);
}
//返回默认建议大小
QSize SWBtn::sizeHint() const
{
return minimumSizeHint();
}
//返回建议最小大小
QSize SWBtn::minimumSizeHint() const
{
//若按构造函数指定大小 则尺寸为2*(16+3),16+2*3 尺寸为(38*22)像素
return QSize(2*(m_SwBtn_Height+m_SwBtn_Margin),m_SwBtn_Height+2*m_SwBtn_Margin);
}
//滑动槽函数定义 改变小圆圈的位置 每10ms刷新一次绘图事件
void SWBtn::SwBtn_Slide()
{
// if(m_SwBtn_Status){ //打开状态
// m_SwBtn_X+=1;
// if(m_SwBtn_X>=width()-m_SwBtn_Height) //x到22时
// m_SwBtn_timer.stop();
// }
// else{
// m_SwBtn_X-=1;
// if(m_SwBtn_X<=m_SwBtn_Height/2) //x到8时
// m_SwBtn_timer.stop();
// }
if(m_SwBtn_Status){ //打开状态
m_SwBtn_X+=1;
if(m_SwBtn_X>=width()-height()) //x到16时 直接更新X坐标为宽度减高度
m_SwBtn_timer.stop();
}
else{
m_SwBtn_X-=1;
if(m_SwBtn_X<=0) //x到0时 X坐标直接从0开始
m_SwBtn_timer.stop();
}
update(); //更新绘图事件
}
具体的实现代码,在别的Widget窗口实现如下:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
BTN1=new SWBtn(ui->widget_1);
BTN2=new SWBtn(ui->widget_1);
BTN1->move(50,50);
BTN2->move(50,100);
BTN3=new MY_SwitchButton(ui->widget_1);
BTN3->move(50,150);
}
Widget::~Widget()
{
delete ui;
}
具体实现的效果图如下所示:

?欢迎交流讨论,目前也是一个正在学习QT的学习者。欢迎大家过来指正讨论。
|