Qt之自定义控件(滑动开关按钮)
说明
本文主要介绍QT的两种滑动开关按钮的实现,附上源码记录以备二次开发
源码附基本注释
滑动开关效果:
主要实现
重写鼠标按下事件(mousePressEvent)、释放事件(mouseReleaseEvent),用于切换开关状态。
重写绘制事件(paintEvent),用于绘制开关效果。
使用QTimer,定时刷新,让开关切换时产生动画效果。
实现源码一
(作者是老张同学)
mybutton.h
#ifndef MYBUTTON_H
#define MYBUTTON_H
#include <QWidget>
class myButton : public QWidget
{
Q_OBJECT
public:
explicit myButton(QWidget *parent = 0);
void mouseReleaseEvent(QMouseEvent *); //鼠标抬起时间
int ii; // 开关标记:开为1,关为0
int jj; //初始化标记
protected:
void paintEvent(QPaintEvent *event); //绘画事件,初始化一次,update()更新
signals:
void buttonChange();//信号,按钮改变发出信号
public slots:
};
#endif // MYBUTTON_H
mybutton.cpp
#include "mybutton.h"
#include <QPainter>
myButton::myButton(QWidget *parent) :
QWidget(parent)
{
resize(50,35);
ii=0;//按钮默认关闭
jj=0;//jj=1初始化阶段
//update();
}
//绘制按钮的函数
void myButton::paintEvent(QPaintEvent *){
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
if(jj==0){ // 初始化,绘制初始化状态按钮
painter.setPen(Qt::NoPen);
if(ii==0){
painter.setBrush(Qt::gray);
}
else if(ii==1){
painter.setBrush(Qt::green);
}
QRectF re(1,1,20,20);
int startAngle = 90*16;
int endAngel = 180*16;
painter.drawPie(re,startAngle,endAngel);
painter.drawRect(11,1,10,20);
QRectF re2(11,1,20,20);
int startAngle2 = -90*16;
int endAngel2 = 180*16;
painter.drawPie(re2,startAngle2,endAngel2);
if(ii==0){ // 关闭状态
painter.setBrush(Qt::yellow);
painter.drawEllipse(2,2,18,18);
}
else if(ii==1){ // 打开状态
painter.setBrush(Qt::yellow);
painter.drawEllipse(12,2,18,18);
}
jj=1;
}
else{
// 绘制状态改变后的按钮
painter.setPen(Qt::NoPen);
if(ii==1){
painter.setBrush(Qt::gray);
}
else if(ii==0){
painter.setBrush(Qt::green);
}
QRectF re(1,1,20,20);//点
int startAngle = 90*16;
int endAngel = 180*16;
painter.drawPie(re,startAngle,endAngel);
painter.drawRect(11,1,10,20);
QRectF re2(11,1,20,20);
int startAngle2 = -90*16;
int endAngel2 = 180*16;
painter.drawPie(re2,startAngle2,endAngel2);
if(ii==0){ // 打开
painter.setBrush(Qt::yellow);
painter.drawEllipse(12,2,18,18);
ii=1;
}
else if(ii==1){ // 关闭
painter.setBrush(Qt::yellow);
painter.drawEllipse(2,2,18,18);
ii=0;
}
emit buttonChange();//发出信号
}
}
//鼠标抬起事件,调用update,重新绘制按钮
void myButton::mouseReleaseEvent(QMouseEvent *){
update();
}
zzz.h(主窗口头文件)
#ifndef ZZZ_H
#define ZZZ_H
#include "mybutton.h"
#include <QWidget>
#include <QMainWindow>
#include <QtGui>
namespace Ui {
class zzz;
}
class zzz : public QWidget
{
Q_OBJECT
public:
explicit zzz(QWidget *parent = 0);
~zzz();
myButton *btn1;
myButton *btn2;
myButton *btn3;
QLabel *la;
public slots:
void textChange();
private:
Ui::zzz *ui;
};
#endif // ZZZ_H
zzz.cpp(主窗口头文件)
#include "zzz.h"
#include "ui_zzz.h"
#include <QtGui>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
#include <QLabel>
zzz::zzz(QWidget *parent) :
QWidget(parent),
ui(new Ui::zzz)
{
QVBoxLayout *layout = new QVBoxLayout();
btn1 = new myButton;
QGroupBox *gb1 = new QGroupBox(tr("switch1"));
QHBoxLayout *l1 = new QHBoxLayout();
l1->addWidget(btn1);
gb1->setLayout(l1);
btn2 = new myButton;
QGroupBox *gb2 = new QGroupBox(tr("switch2"));
QHBoxLayout *l2 = new QHBoxLayout();
l2->addWidget(btn2);
gb2->setLayout(l2);
btn3 = new myButton;
QGroupBox *gb3 = new QGroupBox(tr("switch3"));
QHBoxLayout *l3 = new QHBoxLayout();
l3->addWidget(btn3);
gb3->setLayout(l3);
layout->addWidget(gb1);
layout->addWidget(gb2);
layout->addWidget(gb3);
QString str = QString(tr(""));
if(btn1->ii==0){
str.append("1:off;");
}else{
str.append("1:on");
}
if(btn2->ii==0){
str.append("2:off;");
}else{
str.append("2:on");
}
if(btn3->ii==0){
str.append("3:off.");
}else{
str.append("3:on.");
}
la = new QLabel(str);
layout->addWidget(la);
setLayout(layout);
connect(btn1,SIGNAL(buttonChange()),this,SLOT(textChange()));
connect(btn2,SIGNAL(buttonChange()),this,SLOT(textChange()));
connect(btn3,SIGNAL(buttonChange()),this,SLOT(textChange()));
resize(200,300);
}
void zzz::textChange(){
QString str = QString(tr(""));
if(btn1->ii==0){
str.append("1:off;\t");
}else{
str.append("1:on;\t");
}
if(btn2->ii==0){
str.append("2:off;\t");
}else{
str.append("2:on;\t");
}
if(btn3->ii==0){
str.append("3:off.");
}else{
str.append("3:on.");
}
la->setText(str);
}
zzz::~zzz()
{
delete ui;
}
main.cpp默认的就行
实现源码二
主要参考自:https://blog.csdn.net/weixin_34348805/article/details/90524983(感谢作者)
SwitchControl.h
#ifndef SWITCH_CONTROL
#define SWITCH_CONTROL
#include <QWidget>
#include <QTimer>
class SwitchControl : public QWidget
{
Q_OBJECT
public:
explicit SwitchControl(QWidget *parent = 0);
// 返回开关状态 - 打开:true 关闭:false
bool isToggled() const;
// 设置开关状态
void setToggle(bool checked);
// 设置背景颜色
void setBackgroundColor(QColor color);
// 设置选中颜色
void setCheckedColor(QColor color);
// 设置不可用颜色
void setDisbaledColor(QColor color);
protected:
// 绘制开关
void paintEvent(QPaintEvent *event);
// 鼠标按下事件
void mousePressEvent(QMouseEvent *event);
// 鼠标释放事件 - 切换开关状态、发射toggled()信号
void mouseReleaseEvent(QMouseEvent *event);
// 大小改变事件
void resizeEvent(QResizeEvent *event);
// 缺省大小
QSize sizeHint();
QSize minimumSizeHint();
signals:
// 状态改变时,发射信号
void toggled(bool checked);
private slots:
// 状态切换时,用于产生滑动效果
void onTimeout();
private:
bool m_bChecked; // 是否选中
QColor m_background; // 背景颜色
QColor m_checkedColor; // 选中颜色
QColor m_disabledColor; // 不可用颜色
QColor m_thumbColor; // 拇指颜色
qreal m_radius; // 圆角
qreal m_nX; // x点坐标
qreal m_nY; // y点坐标
qint16 m_nHeight; // 高度
qint16 m_nMargin; // 外边距
QTimer m_timer; // 定时器
};
#endif // SWITCH_CONTROL
SwitchControl.cpp
#include <QPainter>
#include <QMouseEvent>
#include "SwitchControl.h"
SwitchControl::SwitchControl(QWidget *parent)
: QWidget(parent),
m_nHeight(16),
m_bChecked(false),
m_radius(8.0),
m_nMargin(3),
m_checkedColor(0, 150, 136),
m_thumbColor(Qt::white),
m_disabledColor(190, 190, 190),
m_background(Qt::black)
{
// 鼠标滑过光标形状 - 手型
setCursor(Qt::PointingHandCursor);
// 连接信号槽
connect(&m_timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
}
// 绘制开关
void SwitchControl::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
painter.setPen(Qt::NoPen);
painter.setRenderHint(QPainter::Antialiasing);
QPainterPath path;
QColor background;
QColor thumbColor;
qreal dOpacity;
if (isEnabled()) { // 可用状态
if (m_bChecked) { // 打开状态
background = m_checkedColor;
thumbColor = m_checkedColor;
dOpacity = 0.600;
} else { //关闭状态
background = m_background;
thumbColor = m_thumbColor;
dOpacity = 0.800;
}
} else { // 不可用状态
background = m_background;
dOpacity = 0.260;
thumbColor = m_disabledColor;
}
// 绘制大椭圆
painter.setBrush(background);
painter.setOpacity(dOpacity);
path.addRoundedRect(QRectF(m_nMargin, m_nMargin, width() - 2 * m_nMargin, height() - 2 * m_nMargin), m_radius, m_radius);
painter.drawPath(path.simplified());
// 绘制小椭圆
painter.setBrush(thumbColor);
painter.setOpacity(1.0);
painter.drawEllipse(QRectF(m_nX - (m_nHeight / 2), m_nY - (m_nHeight / 2), height(), height()));
}
// 鼠标按下事件
void SwitchControl::mousePressEvent(QMouseEvent *event)
{
if (isEnabled()) {
if (event->buttons() & Qt::LeftButton) {
event->accept();
} else {
event->ignore();
}
}
}
// 鼠标释放事件 - 切换开关状态、发射toggled()信号
void SwitchControl::mouseReleaseEvent(QMouseEvent *event)
{
if (isEnabled()) {
if ((event->type() == QMouseEvent::MouseButtonRelease) && (event->button() == Qt::LeftButton)) {
event->accept();
m_bChecked = !m_bChecked;
emit toggled(m_bChecked);
m_timer.start(2);
} else {
event->ignore();
}
}
}
// 大小改变事件
void SwitchControl::resizeEvent(QResizeEvent *event)
{
m_nX = m_nHeight / 2;
m_nY = m_nHeight / 2;
QWidget::resizeEvent(event);
}
// 默认大小
QSize SwitchControl::sizeHint()
{
return minimumSizeHint();
}
// 最小大小
QSize SwitchControl::minimumSizeHint()
{
return QSize(2 * (m_nHeight + m_nMargin), m_nHeight + 2 * m_nMargin);
}
// 切换状态 - 滑动
void SwitchControl::onTimeout()
{
if (m_bChecked) {
m_nX += 1;
if (m_nX >= width() - m_nHeight)
m_timer.stop();
} else {
m_nX -= 1;
if (m_nX <= m_nHeight / 2)
m_timer.stop();
}
update();
}
// 返回开关状态 - 打开:true 关闭:false
bool SwitchControl::isToggled() const
{
return m_bChecked;
}
// 设置开关状态
void SwitchControl::setToggle(bool checked)
{
m_bChecked = checked;
m_timer.start(10);
}
// 设置背景颜色
void SwitchControl::setBackgroundColor(QColor color)
{
m_background = color;
}
// 设置选中颜色
void SwitchControl::setCheckedColor(QColor color)
{
m_checkedColor = color;
}
// 设置不可用颜色
void SwitchControl::setDisbaledColor(QColor color)
{
m_disabledColor = color;
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include<switchcontrol.h>
#include<QtGui>
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QLabel *label1;
QLabel *label2;
QLabel *label3;
private:
Ui::MainWindow *ui;
public slots:
void onToggled1(bool bChecked);
void onToggled2(bool bChecked);
void onToggled3(bool bChecked);
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QDebug>
#include <QtGui>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//SwitchControl *pSwitchControl = new SwitchControl(this);
//SwitchControl *pGreenSwitchControl = new SwitchControl(this);
//SwitchControl *pDisabledSwitchControl = new SwitchControl(this);
// 设置状态、样式
// pGreenSwitchControl->setToggle(true);
// pGreenSwitchControl->setCheckedColor(QColor(0, 160, 230));
// pDisabledSwitchControl->setDisabled(true);
// pDisabledSwitchControl->setToggle(true);
// 连接信号槽
////connect(pSwitchControl, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool)));
QVBoxLayout *layout = new QVBoxLayout();
SwitchControl *btn1 = new SwitchControl(this);
QGroupBox *gb1 = new QGroupBox(tr("LED1"));
QHBoxLayout *l1 = new QHBoxLayout();
label1 = new QLabel(tr("OFF"));
l1->addWidget(label1);
l1->addWidget(btn1);
gb1->setLayout(l1);
SwitchControl *btn2 = new SwitchControl(this);
QGroupBox *gb2 = new QGroupBox(tr("LED2"));
QHBoxLayout *l2 = new QHBoxLayout();
label2 = new QLabel(tr("OFF"));
l2->addWidget(label2);
l2->addWidget(btn2);
gb2->setLayout(l2);
SwitchControl *btn3 = new SwitchControl(this);
QGroupBox *gb3 = new QGroupBox(tr("LED3"));
QHBoxLayout *l3 = new QHBoxLayout();
label3 = new QLabel(tr("OFF"));
l3->addWidget(label3);
l3->addWidget(btn3);
gb3->setLayout(l3);
connect(btn1, SIGNAL(toggled(bool)), this, SLOT(onToggled1(bool)));
connect(btn2, SIGNAL(toggled(bool)), this, SLOT(onToggled2(bool)));
connect(btn3, SIGNAL(toggled(bool)), this, SLOT(onToggled3(bool)));
layout->addWidget(gb1);
layout->addWidget(gb2);
layout->addWidget(gb3);
QWidget *window = new QWidget;
window->setLayout(layout);
setWindowTitle(tr("bean"));
setCentralWidget(window);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onToggled1(bool bChecked)
{
qDebug() << "State : " << bChecked;
if(bChecked){
label1->setText("ON");
label1->setStyleSheet("color:red");
}
else{
label1->setText("OFF");
label1->setStyleSheet("color:black");
}
}
void MainWindow::onToggled2(bool bChecked)
{
qDebug() << "State : " << bChecked;
if(bChecked){
label2->setText("ON");
label2->setStyleSheet("color:red");
}
else{
label2->setText("OFF");
label2->setStyleSheet("color:black");
}
}
void MainWindow::onToggled3(bool bChecked)
{
qDebug() << "State : " << bChecked;
if(bChecked){
label3->setText("ON");
label3->setStyleSheet("color:red");
}
else{
label3->setText("OFF");
label3->setStyleSheet("color:black");
}
}
main.cpp默认
以上两个程序都有些小bug,总体上不影响使用,可以在此基础上修改