在Qt中实现SwitchButton(开关按钮)

Qt的官方UI控件中是并不包含SwitchButton的,不过可以直接手动创建一个类作为switchbutton来实现这样的效果。

效果图象:

switchbutton.h代码:

cpp 复制代码
#ifndef SWITCHBUTTON_H
#define SWITCHBUTTON_H

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

class SwitchButton : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(int sliderPosition READ getSliderPosition WRITE setSliderPosition)

public:
    explicit SwitchButton(QWidget *parent = nullptr);

    // 获取当前状态
    bool isChecked() const { return m_checked; }

    // 设置状态
    void setChecked(bool checked);

    // 设置背景颜色
    void setBackgroundColor(const QColor &onColor, const QColor &offColor);

    // 设置滑块颜色
    void setSliderColor(const QColor &color);

signals:
    // 状态改变信号
    void toggled(bool checked);

protected:
    void paintEvent(QPaintEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;

private:
    int getSliderPosition() const { return m_sliderPosition; }
    void setSliderPosition(int position);

    void updateSliderPosition();

    bool m_checked = false;
    int m_sliderPosition = 0;

    QColor m_onColor = QColor(0, 150, 255);
    QColor m_offColor = QColor(150, 150, 150);
    QColor m_sliderColor = Qt::white;

    int m_sliderMargin = 2;
    int m_sliderRadius = 0;

    QPropertyAnimation *m_animation;
};

#endif // SWITCHBUTTON_H

switchbutton.cpp代码

cpp 复制代码
#include "switchbutton.h"

SwitchButton::SwitchButton(QWidget *parent)
    : QWidget(parent)
{
    setFixedSize(60, 30);

    // 初始化动画
    m_animation = new QPropertyAnimation(this, "sliderPosition");
    m_animation->setDuration(200);

    updateSliderPosition();
}

void SwitchButton::setChecked(bool checked)
{
    if (m_checked != checked) {
        m_checked = checked;
        updateSliderPosition();
        update();
        emit toggled(m_checked);
    }
}

void SwitchButton::setBackgroundColor(const QColor &onColor, const QColor &offColor)
{
    m_onColor = onColor;
    m_offColor = offColor;
    update();
}

void SwitchButton::setSliderColor(const QColor &color)
{
    m_sliderColor = color;
    update();
}

void SwitchButton::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    // 绘制背景
    QColor bgColor = m_checked ? m_onColor : m_offColor;
    painter.setBrush(bgColor);
    painter.setPen(Qt::NoPen);

    // 绘制圆角矩形背景
    int cornerRadius = height() / 2;
    painter.drawRoundedRect(rect(), cornerRadius, cornerRadius);

    // 绘制滑块
    painter.setBrush(m_sliderColor);

    int sliderDiameter = height() - 2 * m_sliderMargin;
    QRect sliderRect(m_sliderPosition, m_sliderMargin,
                     sliderDiameter, sliderDiameter);

    painter.drawEllipse(sliderRect);
}

void SwitchButton::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        setChecked(!m_checked);
        event->accept();
    } else {
        QWidget::mousePressEvent(event);
    }
}

void SwitchButton::resizeEvent(QResizeEvent *event)
{
    Q_UNUSED(event);
    updateSliderPosition();
}

void SwitchButton::setSliderPosition(int position)
{
    if (m_sliderPosition != position) {
        m_sliderPosition = position;
        update();
    }
}

void SwitchButton::updateSliderPosition()
{
    int startPos = m_sliderMargin;
    int endPos = width() - height() + m_sliderMargin;

    if (m_checked) {
        m_sliderPosition = endPos;
    } else {
        m_sliderPosition = startPos;
    }

    // 设置动画
    m_animation->stop();
    m_animation->setStartValue(m_sliderPosition);
    m_animation->setEndValue(m_checked ? endPos : startPos);
    m_animation->start();
}

mainwindow.h代码

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLabel>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "switchbutton.h"

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void onSwitch1Toggled(bool checked);
    void onSwitch2Toggled(bool checked);
    void onSwitch3Toggled(bool checked);

private:
    void setupUI();

    SwitchButton *m_switch1;
    SwitchButton *m_switch2;
    SwitchButton *m_switch3;

    QLabel *m_statusLabel1;
    QLabel *m_statusLabel2;
    QLabel *m_statusLabel3;
};

#endif // MAINWINDOW_H

mainwindow.cpp代码

cpp 复制代码
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setupUI();

    // 连接信号槽
    connect(m_switch1, &SwitchButton::toggled, this, &MainWindow::onSwitch1Toggled);
    connect(m_switch2, &SwitchButton::toggled, this, &MainWindow::onSwitch2Toggled);
    connect(m_switch3, &SwitchButton::toggled, this, &MainWindow::onSwitch3Toggled);
}

MainWindow::~MainWindow()
{
}

void MainWindow::setupUI()
{
    QWidget *centralWidget = new QWidget(this);
    setCentralWidget(centralWidget);

    QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);

    // 创建第一个开关
    QHBoxLayout *layout1 = new QHBoxLayout();
    m_switch1 = new SwitchButton(this);
    m_statusLabel1 = new QLabel("开关1: 关闭", this);
    layout1->addWidget(new QLabel("WiFi:", this));
    layout1->addWidget(m_switch1);
    layout1->addWidget(m_statusLabel1);
    layout1->addStretch();

    // 创建第二个开关
    QHBoxLayout *layout2 = new QHBoxLayout();
    m_switch2 = new SwitchButton(this);
    m_switch2->setBackgroundColor(QColor(0, 200, 0), QColor(100, 100, 100)); // 绿色开启状态
    m_statusLabel2 = new QLabel("开关2: 关闭", this);
    layout2->addWidget(new QLabel("蓝牙:", this));
    layout2->addWidget(m_switch2);
    layout2->addWidget(m_statusLabel2);
    layout2->addStretch();

    // 创建第三个开关
    QHBoxLayout *layout3 = new QHBoxLayout();
    m_switch3 = new SwitchButton(this);
    m_switch3->setBackgroundColor(QColor(255, 100, 0), QColor(150, 150, 150)); // 橙色开启状态
    m_switch3->setSliderColor(QColor(240, 240, 240));
    m_statusLabel3 = new QLabel("开关3: 关闭", this);
    layout3->addWidget(new QLabel("飞行模式:", this));
    layout3->addWidget(m_switch3);
    layout3->addWidget(m_statusLabel3);
    layout3->addStretch();

    // 添加到主布局
    mainLayout->addLayout(layout1);
    mainLayout->addLayout(layout2);
    mainLayout->addLayout(layout3);
    mainLayout->addStretch();

    setWindowTitle("Qt SwitchButton 示例");
    resize(300, 200);
}

void MainWindow::onSwitch1Toggled(bool checked)
{
    m_statusLabel1->setText(QString("开关1: %1").arg(checked ? "开启" : "关闭"));
    qDebug() << "WiFi" << (checked ? "已开启" : "已关闭");
}

void MainWindow::onSwitch2Toggled(bool checked)
{
    m_statusLabel2->setText(QString("开关2: %1").arg(checked ? "开启" : "关闭"));
    qDebug() << "蓝牙" << (checked ? "已开启" : "已关闭");
}

void MainWindow::onSwitch3Toggled(bool checked)
{
    m_statusLabel3->setText(QString("开关3: %1").arg(checked ? "开启" : "关闭"));
    qDebug() << "飞行模式" << (checked ? "已开启" : "已关闭");
}
相关推荐
Scott9999HH2 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社3 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海3 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖4 小时前
JDK 26 新特性详解
java·开发语言
马优晨5 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区6 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大7 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai7 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜7 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa7 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio