Qt之自定义控件(滑动开关按钮)+源码

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,总体上不影响使用,可以在此基础上修改

发布了97 篇原创文章 · 获赞 61 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/xbean1028/article/details/105302907