在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 ? "已开启" : "已关闭");
}
相关推荐
wu_jing_sheng016 分钟前
销售数据分析
开发语言·python
haofafa36 分钟前
STL之动态数组
开发语言·c++
earthzhang20211 小时前
【2051】【例3.1】偶数
开发语言·数据结构·算法·青少年编程·图论
专注VB编程开发20年1 小时前
.NET Reflector反编绎,如何移除DLL中的一个公开属性
开发语言·c++·c#
vxiam14xxx2 小时前
【Java Swing 项目】java 聊天系统
java·开发语言·python
znhy@1232 小时前
十三、JS进阶(二)
开发语言·前端·javascript
@木辛梓2 小时前
Linux 线程
linux·开发语言·c++
孤独的追光者3 小时前
使用Qt Designer开发上位机
开发语言·python·qt
m0_736927043 小时前
Java面试场景题及答案总结(2025版持续更新)
java·开发语言·后端·职场和发展
muyouking113 小时前
Rust + WASM + Svelte 深度实战:内存管理、性能权衡与图像处理进阶
开发语言·rust·wasm