Qt 之自定义控件(开关按钮)

Qt 之自定义控件(开关按钮)

    • 原理
    • 源码
    • 运行结果

接触过IOS系统的童鞋们应该对开关按钮很熟悉,在设置里面经常遇到,切换时候的滑动效果比较帅气。
通常说的开关按钮,有两个状态:on、off。
下面,我们利用自定义控件来实现一个开关按钮。

原理

重写鼠标按下事件(mousePressEvent)、释放事件(mouseReleaseEvent),用于切换开关状态。
重写绘制事件(paintEvent),用于绘制开关效果。
使用QTimer,定时刷新,让开关切换时产生动画效果。
其余接口用于扩展,也可自己扩充。

源码

SwitchControl.h

#ifndef SWITCHCONTROL_H
#define SWITCHCONTROL_H


#include <QObject>
#include <QWidget>
#include <QTimer>


class SwitchControl : public QWidget
{
    Q_OBJECT
public:
    explicit SwitchControl(QWidget *parent = nullptr);


    // 返回开关状态 - 打开: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) Q_DECL_OVERRIDE;


    // 鼠标按下事件
    void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;


    // 鼠标释放事件 - 切换开关状态、发射toggled()信号
    void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;


    // 大小改变事件
    void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;




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 // SWITCHCONTROL_H

SwitchControl.cpp

#include <QPainter>
#include <QMouseEvent>
#include "switchcontrol.h"


SwitchControl::SwitchControl(QWidget *parent)
    : QWidget(parent),
      m_bChecked(false),
      m_background(Qt::black),
      m_checkedColor(QColor(0, 150, 136)),
      m_disabledColor(QColor(190, 190, 190)),
      m_thumbColor(Qt::white),
      m_radius(32.0),
      m_nHeight(64),
      m_nMargin(0)
{
    // 鼠标滑过光标形状 - 手型
    setCursor(Qt::PointingHandCursor);
    setFixedSize(m_nHeight*3, m_nHeight);


    // 连接信号槽
    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;
    QString stateStr;
    QRectF rect;
    QPen pen(QBrush(QColor(255, 255, 255)), 1);
    QFont font("黑体", 28, QFont::Normal);


    if (isEnabled()) { // 可用状态


        if (m_bChecked) { // 打开状态
            background = m_checkedColor;
            thumbColor = m_checkedColor;
            dOpacity = 0.600;
            stateStr = QString("On");
            QFontMetrics fmt(font);
            int textWidth = fmt.horizontalAdvance(stateStr);
            int textHeight = fmt.height();
            rect = QRectF(height()*0.3, height()*0.1, textWidth, textHeight);


        } else { //关闭状态
            background = m_background;
            thumbColor = m_thumbColor;
            dOpacity = 0.800;
            stateStr = QString("Off");
            QFontMetrics fmt(font);
            int textWidth = fmt.horizontalAdvance(stateStr);
            int textHeight = fmt.height();
            rect = QRectF(height()*1.3, height()*0.1, textWidth, textHeight);


        }
    } 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());
    qDebug("x:%d, y:%d, w:%d, h:%d\n", m_nMargin, m_nMargin, width() - 2 * m_nMargin, height() - 2 * m_nMargin);


    // 绘制小椭圆
    painter.setBrush(thumbColor);
    painter.setOpacity(1.0);
    painter.drawEllipse(QRectF(m_nX - (m_nHeight / 2), m_nY - (m_nHeight / 2), height(), height()));


    painter.setPen(pen);
    painter.setFont(font);
    painter.drawText(rect, Qt::AlignCenter, stateStr);
}


// 鼠标按下事件
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(3);
        } else {
            event->ignore();
        }
    }
}


// 大小改变事件
void SwitchControl::resizeEvent(QResizeEvent *event)
{
    m_nX = m_nHeight / 2;
    m_nY = m_nHeight / 2;
    QWidget::resizeEvent(event);
}




// 切换状态 - 滑动
void SwitchControl::onTimeout()
{
    if (m_bChecked) {
        m_nX += 1;
        if (m_nX >= width() - m_nHeight/2)
            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::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);


    QVBoxLayout* vbox = new QVBoxLayout;
    ui->centralwidget->setLayout(vbox);
    vbox->addWidget(pSwitchControl, 1);
    vbox->addWidget(pGreenSwitchControl);
    vbox->addWidget(pDisabledSwitchControl);
    // 设置状态、样式
    pGreenSwitchControl->setToggle(true);
    pGreenSwitchControl->setCheckedColor(QColor(0, 160, 230));
    pGreenSwitchControl->setBackgroundColor(QColor(255, 99, 71));
    pDisabledSwitchControl->setEnabled(true);
    pDisabledSwitchControl->setToggle(true);
    // 连接信号槽
    connect(pSwitchControl, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool)));


}

void MainWindow::onToggled(bool bChecked)
{
    qDebug() << "State : " << bChecked;
}

运行结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/144486.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【LSNET】用自己的数据复现LSNet变化检测代码

之前讲过LSNet网络的论文详解了,感兴趣的童鞋请移步【LSNET】变化检测。 本篇主要是讲解如何用自己的数据复现代码【python】。 🌺论文:paper 🌺代码: code 目录 🔔🔔1.环境安装

linux下安装向日葵

https://sunlogin.oray.com/download/linux?typepersonal下载 在文件所在位置的空白处右键&#xff08;在此处打开终端&#xff09; 输入命令&#xff1a; sudo dpkg -i 文件名.deb &#xff08;文件名为下载的deb文件名字&#xff09;/usr/local/sunlogin/bin/sunlogincl…

keepalived 的安装部署及使用详细完整版

架构 1.安装 yum install keepalived -ysystemctl enable keepalivedsystemctl restart keepalivedsystemctl status keepalived2.部署配置样例 vim /etc/keepalived/keepalived.conf global_defs {router_id PROXYSQL_HAscript_user rootenable_script_security } vrrp_scri…

掉瓶子小游戏

欢迎来到程序小院 掉瓶子 玩法&#xff1a;旋转的瓶子&#xff0c;根据瓶子方向&#xff0c;点击鼠标左键瓶子掉落&#xff0c;从桌面中间掉下即得1分&#xff0c;卡在桌边瓶子碎了游戏结束&#xff0c;快去掉瓶子吧^^。开始游戏https://www.ormcc.com/play/gameStart/203 htm…

TSINGSEE青犀视频平台EasyCVR自定义可视化页面一览

视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频流&#xff0c;也能支…

【科研新手指南2】「NLP+网安」相关顶级会议期刊 投稿注意事项+会议等级+DDL+提交格式

「NLP网安」相关顶级会议&期刊投稿注意事项 写在最前面一、会议ACL (The Annual Meeting of the Association for Computational Linguistics)IH&MMSec (The ACM Workshop on Information Hiding, Multimedia and Security)CCS (The ACM Conference on Computer and Co…

使用JDBC连接数据库出现The server time zone value ‘�й���׼ʱ��‘ is unrecognized 的解决方案

看到网上的大佬们说是引入的依赖版本太高所以导致了时区有问题 但是我把依赖的版本改低了还是报错 用另一种办法直接在配置文件中修改url然后成功解决 spring:datasource:url: jdbc:mysql://127.0.0.1:3306/datasource?useUnicodetrue&characterEncodingutf8&useSSL…

山西电力市场日前价格预测【2023-11-15】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-11-15&#xff09;山西电力市场全天平均日前电价为237.36元/MWh。其中&#xff0c;最高日前电价为360.45元/MWh&#xff0c;预计出现在00:15。最低日前电价为0.00元/MWh&#xff0c;预计出…

中国人民大学与加拿大女王大学金融硕士——热爱会穿越时间,埋在心底的读研梦也是

随着时光的流转&#xff0c;我们都在跌跌撞撞中成长&#xff0c;改变&#xff0c;但有一种东西是永恒的&#xff0c;那就是我们对梦想的渴望。那些被尘封的读研梦想&#xff0c;如同穿越漫长岁月&#xff0c;等待在未来的某一天重见天日。梦想&#xff0c;就如同热爱一样&#…

如何查找领取淘宝优惠券?

如何查找领取淘宝优惠券&#xff1f; 1、手机安装「草柴」领券应用后&#xff0c;打开手机淘宝&#xff0c;挑选要购买的商品&#xff0c;并点击分享复制链接&#xff1b; 2、复制淘宝商品链接后&#xff0c;打开「草柴」APP&#xff0c;将复制的链接粘贴并查询该商品优惠券及…

【机器学习】朴素贝叶斯算法:多项式、高斯、伯努利,实例应用(心脏病预测)

1. 朴素贝叶斯模型 对于不同的数据&#xff0c;我们有不同的朴素贝叶斯模型进行分类。 1.1 多项式模型 &#xff08;1&#xff09;如果特征是离散型数据&#xff0c;比如文本这些&#xff0c;推荐使用多项式模型来实现。该模型常用于文本分类&#xff0c;特别是单词&#xf…

竞赛选题 深度学习的智能中文对话问答机器人

文章目录 0 简介1 项目架构2 项目的主要过程2.1 数据清洗、预处理2.2 分桶2.3 训练 3 项目的整体结构4 重要的API4.1 LSTM cells部分&#xff1a;4.2 损失函数&#xff1a;4.3 搭建seq2seq框架&#xff1a;4.4 测试部分&#xff1a;4.5 评价NLP测试效果&#xff1a;4.6 梯度截断…

石原子科技亮相2023成都市信息领域新产品发布会

2023年11月13日至15日&#xff0c;由成都市互联网信息办公室、四川天府新区管委会、成都市经信局市新经济委、成都市农业农村局指导的以“信息创造价值 创新引领未来”为主题的成都市信息领域新产品发布会在科创生态岛1号馆举行。围绕人工智能、区块链、数字化绿色化、数字乡村…

keepalived+haproxy配置集群和负载均衡

1、简介 1.1. Keepalived Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以利用其来避免单点故障。一个LVS服务会有2台服务器运行Keepalived,一台为主服务器(MASTER),一台为备份服务器(BACKUP),但是对外表现为一个虚拟IP,主服务器会发送特定的消息给备…

Microsoft Forms

Microsoft Forms官网&#xff1a;Microsoft Forms - Free tool to create online surveys, forms, polls, and quizzes Microsoft Forms主要用来自定义一些表单和问卷调查 点击新建表单 填写完表单名称之后&#xff0c;下面就可以添加问题了&#xff0c;可以选择多种提问方式…

设计模式系列之最终篇:大盘点

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概4000多字&#xff0c;预计阅读时间长需要3分钟。本篇文章的实战性、理论性较强&#xff0c;是一篇质量分数较高的技术干货文章&#x…

盘点72个Python网站项目Python爱好者不容错过

盘点72个Python网站项目Python爱好者不容错过 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 链接&#xff1a;https://pan.baidu.com/s/12twY8iZYhAG8BuyYXM7_bw?pwd8888 提取码&#xff1a;8888 项目名称 dailyfreshpython…

拼图游戏,开源代码

拼图游戏 最近玩了玩孩子的拼图游戏&#xff0c;感觉还挺好玩的&#xff0c;心血来潮要不动手做一个吧&#xff0c;偷懒摸鱼的时候可以来一把。 以下就是拼图游戏的界面截图。 体验地址 代码开源地址 心得体会 虽说是一个小游戏&#xff0c;但是需要注意的地方还是挺多的 方…

技术探秘:开发抖音小程序实现餐饮团购的关键步骤

本文将深入研究在抖音小程序上开发餐饮团购功能的关键步骤&#xff0c;揭示技术探秘背后的秘密。 一、了解抖音小程序开发环境 注册成为抖音小程序开发者&#xff0c;配置开发工具&#xff0c;并确保您的开发环境设置正确&#xff0c;以便顺利进行后续的开发工作。 二、制定团…

在 Android 上简单安全地登录——使用凭证管理器和密钥

我踏马很高兴地听说&#xff0c; Credential Manager的公开版本将于 11 月 1 日开始提供。Credential Manager 为 Android 带来了身份验证的未来&#xff0c;简化了用户登录应用程序和网站的方式&#xff0c;同时使其更加安全。 登录可能具有挑战性 - 密码经常使用&#xff0c…
最新文章