[Qt学习笔记]Qt实现自定义控件SwitchButton开关按钮
1、功能介绍
在项目UI中使用较多的打开/关闭的开关按钮,一般都是找图片去做效果,比如说如下的图像来表征打开或关闭。
![]() | ![]() | ![]() |
---|
如果想要控件有打开/关闭的动画效果或比较好的视觉效果,这里就可以使用自定义控件,使用Painter来绘制控件。软件最终的效果如上图三:
2、主要的实现绘制代码
绘制背景区域
void SwitchButton::drawBackGround(QPainter *painter)
{painter->save();painter->setPen(Qt::NoPen);QColor bgColor = m_checked ? m_bgColorOn : m_bgColorOff;if (isEnabled()) {bgColor.setAlpha(140);}painter->setBrush(bgColor);QRect rect(0, 0, width(), height());int side = qMin(width(), height());//左侧半圆QPainterPath path1;path1.addEllipse(rect.x(), rect.y(), side, side);//右侧半圆QPainterPath path2;path2.addEllipse(rect.width() - side, rect.y(), side, side);//中间的矩形QPainterPath path3;path3.addRect(rect.x() + side / 2, rect.y(), rect.width() - side, height());QPainterPath path = path1 + path2 + path3;painter->drawPath(path);//绘制文本//滑块半径int sliderWidth = qMin(height(), width()) - m_space * 2 - 5;if (m_checked){QRect textRect(0, 0, width() - sliderWidth, height());painter->setPen(QPen(m_textColor));painter->drawText(textRect, Qt::AlignCenter, m_textOn);} else {QRect textRect(sliderWidth, 0, width() - sliderWidth, height());painter->setPen(QPen(m_textColor));painter->drawText(textRect, Qt::AlignCenter, m_textOff);}painter->restore();
}
绘制滑块
void SwitchButton::drawSlider(QPainter *painter)
{painter->save();painter->setPen(Qt::NoPen);QColor color = m_checked ? m_sliderColorOn : m_sliderColorOff;painter->setBrush(QBrush(color));int sliderWidth = qMin(width(), height()) - m_space * 2;QRect rect(m_space + m_startX, m_space, sliderWidth, sliderWidth);painter->drawEllipse(rect);painter->restore();
}
这里引入了滑块动画效果,设定一个定时器,根据滑块的距离设置一个动画的效果
m_timer = new QTimer(this);m_timer->setInterval(30);connect(m_timer, SIGNAL(timeout()), this, SLOT(UpdateValue()));void SwitchButton::UpdateValue()
{if (m_checked) {if (m_startX < m_endX) {m_startX += m_step;} else {m_startX = m_endX;m_timer->stop();}} else {if (m_startX > m_endX) {m_startX -= m_step;} else {m_startX = m_endX;m_timer->stop();}}update();
}
3、功能实现源码
switchButton.h
#ifndef SWITCHBUTTON_H
#define SWITCHBUTTON_H#include <QObject>
#include <QWidget>
#include <QTimer>
#include <QColor>class SwitchButton : public QWidget
{Q_OBJECT
public:explicit SwitchButton(QWidget *parent = nullptr);signals:void statusChanged(bool checked);public slots:private slots:void UpdateValue();private:void drawBackGround(QPainter *painter);void drawSlider(QPainter *painter);protected:void paintEvent(QPaintEvent *event);void mousePressEvent(QMouseEvent *event);private://滑块距离边界距离int m_space;//圆角角度int m_radius;//是否选中bool m_checked;//是否显示文本bool m_showText;//是否显示圆bool m_showCircle;//是否使用动画bool m_animation;//打开时候背景色QColor m_bgColorOn;//关闭时候背景色QColor m_bgColorOff;//打开时候滑块颜色QColor m_sliderColorOn;//关闭时候滑块颜色QColor m_sliderColorOff;//文字颜色QColor m_textColor;//打开时候文字QString m_textOn;//关闭时候文字QString m_textOff;//动画定时器QTimer *m_timer;//动画步长int m_step;//滑块开始X轴坐标int m_startX;//滑块介绍X轴坐标int m_endX;public:int space() const;int radius() const;bool checked() const;bool showText() const;bool showCircle() const;bool animation() const;QColor bgColorOn() const;QColor bgColorOff() const;QColor sliderColorOn() const;QColor sliderColorOff() const;QColor textColor() const;QString textOn() const;QString textOff() const;int step() const;int startX() const;int endX() const;public Q_SLOTS:void setSpace(int space);void setRadius(int radius);void setChecked(bool checked);void setShowText(bool show);void setShowCircle(bool show);void setAnimation(bool ok);void setBgColorOn(const QColor &color);void setBgColorOff(const QColor &color);void setSliderColorOn(const QColor &color);void setSliderColorOff(const QColor &color);void setTextColor(const QColor &color);void setTextOn(const QString &text);void setTextOff(const QString &text);// void setStep(int step);
// void setStartX(int startX);
// void setEndX(int endX);
};#endif // SWITCHBUTTON_H
switchButton.cpp
#pragma execution_character_set("utf-8")
#include "SwitchButton.h"
#include <QPainter>SwitchButton::SwitchButton(QWidget *parent) : QWidget(parent)
{m_space = 2;m_radius = 5;m_checked = false;m_showText = true;m_showText = false;m_animation = true;m_bgColorOn = QColor(21, 156, 119);m_bgColorOff = QColor(111, 122, 126);m_sliderColorOn = QColor(255, 255, 255);m_sliderColorOff = QColor(255, 255, 255);m_textColor = QColor(255, 255, 255);m_textOn = "开启";m_textOff = "关闭";m_step = 0;m_startX = 0;m_endX = 0;m_timer = new QTimer(this);m_timer->setInterval(30);connect(m_timer, SIGNAL(timeout()), this, SLOT(UpdateValue()));
}void SwitchButton::drawBackGround(QPainter *painter)
{painter->save();painter->setPen(Qt::NoPen);QColor bgColor = m_checked ? m_bgColorOn : m_bgColorOff;if (isEnabled()) {bgColor.setAlpha(140);}painter->setBrush(bgColor);QRect rect(0, 0, width(), height());int side = qMin(width(), height());//左侧半圆QPainterPath path1;path1.addEllipse(rect.x(), rect.y(), side, side);//右侧半圆QPainterPath path2;path2.addEllipse(rect.width() - side, rect.y(), side, side);//中间的矩形QPainterPath path3;path3.addRect(rect.x() + side / 2, rect.y(), rect.width() - side, height());QPainterPath path = path1 + path2 + path3;painter->drawPath(path);//绘制文本//滑块半径int sliderWidth = qMin(height(), width()) - m_space * 2 - 5;if (m_checked){QRect textRect(0, 0, width() - sliderWidth, height());painter->setPen(QPen(m_textColor));painter->drawText(textRect, Qt::AlignCenter, m_textOn);} else {QRect textRect(sliderWidth, 0, width() - sliderWidth, height());painter->setPen(QPen(m_textColor));painter->drawText(textRect, Qt::AlignCenter, m_textOff);}painter->restore();
}void SwitchButton::drawSlider(QPainter *painter)
{painter->save();painter->setPen(Qt::NoPen);QColor color = m_checked ? m_sliderColorOn : m_sliderColorOff;painter->setBrush(QBrush(color));int sliderWidth = qMin(width(), height()) - m_space * 2;QRect rect(m_space + m_startX, m_space, sliderWidth, sliderWidth);painter->drawEllipse(rect);painter->restore();
}void SwitchButton::paintEvent(QPaintEvent *ev)
{//启用反锯齿QPainter painter(this);painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);//绘制背景drawBackGround(&painter);//绘制滑块drawSlider(&painter);
}void SwitchButton::mousePressEvent(QMouseEvent *ev)
{Q_UNUSED(ev)m_checked = !m_checked;emit statusChanged(m_checked);//计算步长m_step = width() / 10;//计算滑块X轴终点坐标if (m_checked) {m_endX = width() - height();} else {m_endX = 0;}//判断是否使用动画if (m_animation) {m_timer->start();} else{m_startX = m_endX;update();}
}void SwitchButton::UpdateValue()
{if (m_checked) {if (m_startX < m_endX) {m_startX += m_step;} else {m_startX = m_endX;m_timer->stop();}} else {if (m_startX > m_endX) {m_startX -= m_step;} else {m_startX = m_endX;m_timer->stop();}}update();
}int SwitchButton::space() const
{return m_space;
}int SwitchButton::radius() const
{return m_radius;
}bool SwitchButton::checked() const
{return m_checked;
}bool SwitchButton::showText() const
{return m_showText;
}bool SwitchButton::showCircle() const
{return m_showCircle;
}bool SwitchButton::animation() const
{return m_animation;
}QColor SwitchButton::bgColorOn() const
{return m_bgColorOn;
}QColor SwitchButton::bgColorOff() const
{return m_bgColorOff;
}QColor SwitchButton::sliderColorOn() const
{return m_sliderColorOn;
}QColor SwitchButton::sliderColorOff() const
{return m_sliderColorOff;
}QColor SwitchButton::textColor() const
{return m_textColor;
}QString SwitchButton::textOn() const
{return m_textOn;
}QString SwitchButton::textOff() const
{return m_textOff;
}int SwitchButton::step() const
{return m_step;
}int SwitchButton::startX() const
{return m_startX;
}int SwitchButton::endX() const
{return m_endX;
}void SwitchButton::setSpace(int space)
{if (m_space != space) {m_space = space;update();}
}void SwitchButton::setRadius(int radius)
{if (m_radius != radius) {m_radius = radius;update();}
}void SwitchButton::setChecked(bool checked)
{if (m_checked != checked) {m_checked = checked;update();}
}void SwitchButton::setShowText(bool show)
{if (m_showText != show) {m_showText = show;update();}
}void SwitchButton::setShowCircle(bool show)
{if (m_showCircle != show) {m_showCircle = show;update();}
}void SwitchButton::setAnimation(bool ok)
{if (m_animation != ok) {m_animation = ok;update();}
}void SwitchButton::setBgColorOn(const QColor &color)
{if (m_bgColorOn != color) {m_bgColorOn = color;update();}
}void SwitchButton::setBgColorOff(const QColor &color)
{if (m_bgColorOff != color) {m_bgColorOff = color;update();}
}void SwitchButton::setSliderColorOn(const QColor &color)
{if (m_sliderColorOn != color) {m_sliderColorOn = color;update();}
}void SwitchButton::setSliderColorOff(const QColor &color)
{if (m_sliderColorOff != color) {m_sliderColorOff = color;update();}
}void SwitchButton::setTextColor(const QColor &color)
{if (m_textColor != color) {m_textColor = color;update();}
}void SwitchButton::setTextOn(const QString &text)
{if (m_textOn != text) {m_textOn = text;update();}
}void SwitchButton::setTextOff(const QString &text)
{if (m_textOff != text) {m_textOff = text;update();}
}//void SwitchButton::setStep(int step)
//{
// if (m_step != step) {
// m_step = step;
// update();
// }
//}//void SwitchButton::setStartX(int startX)
//{//}//void SwitchButton::setEndX(int endX)
//{//}
4、效果与源码
控件实现的动态效果如下
本小例程的代码放到我的开源gitte项目里,欢迎一起学习,也希望能收获你的小星星。
源码SwitchButton
相关文章:

[Qt学习笔记]Qt实现自定义控件SwitchButton开关按钮
1、功能介绍 在项目UI中使用较多的打开/关闭的开关按钮,一般都是找图片去做效果,比如说如下的图像来表征打开或关闭。 如果想要控件有打开/关闭的动画效果或比较好的视觉效果,这里就可以使用自定义控件,使用Painter来绘制控件。软…...
【工具】mac 环境配置
【待补充 】 一、maven配置 vim ~/.bash_profile export M3_HOME/Users/chenyang/java_utils/apache-maven-3.6.1 export PATH$PATH:$M3_HOME/bin //mvn -v提示Permission denied 没有权限访问 chmod ax /Users/chenyang/java_utils/apache-maven-3.6.1/bin/mvn 二、java…...

【前端寻宝之路】学习和总结HTML的标签属性
🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| 💫个人格言:“没有罗马,那就自己创造罗马~” 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不…...

kafka2.x版本配置SSL进行加密和身份验证
背景:找了一圈资料,都是东讲讲西讲讲,最后我还没搞好,最终决定参考官网说明。 官网指导手册地址:Apache Kafka 需要预备的知识,keytool和openssl 关于keytool的参考:keytool的使用-CSDN博客 …...

Linux和Windows下的文件批量重命名
一、Linux下文件批量重命名 rename命令说明: Usage: rename [options] … Rename files. Options: -v, --verbose explain what is being done -s, --symlink act on the target of symlinks -n, --no-act do not make any changes -o, --no-overwrite don’t overw…...

stm32之GPIO电路介绍
文章目录 1 GPIO介绍2 GPIO的工作模式2.1 浮空输入2.2 上拉输入2.3 下拉输入2.4 模拟输入2.5 开漏输出2.6 推挽输出2.7 复用开漏输出2.8 复用推挽输出2.9 其他 3 应用方式4 常用库函数 1 GPIO介绍 保护二极管:保护引脚,让引脚的电压位于正常的范围施密特…...

Unity Toggle处理状态变化事件
Toggle处理状态变化事件,有两个方法。 法一、通过Inspector面板设置 实现步骤: 在Inspector面板中找到Toggle组件的"On Value Changed"事件。单击""按钮添加一个新的监听器。拖动一个目标对象到"None (Object)"字段&am…...

UE5.1 iClone8 正确导入角色骨骼与动作
使用iClone8插件Auto Setup 附录下载链接 里面有两个文件夹,使用Auto Setup C:\Program Files\Reallusion\Shared Plugins 在UE内新建Plugins,把插件复制进去 在工具栏出现这三个人物的图标就安装成功了 iClone选择角色,导入动作 选择导出FBX UE内直接导入 会出现是否启动插件…...
FFmpeg-- c++实现:pcm和yuv编码
文章目录 流程音频视频 api核心代码audioencoder.haudioencoder.cppvideoencoder.hvideoencoder.cpp pcm和yuv编码为aac和h264,封装为c的AudioEncoder类和VideoEncoder类 流程 音频 初始化音频参数 int InitAAC(int channels, int sample_rate, int bit_rate); 音…...

图解CodeWhisperer的安装使用
🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 📘 CodeWhisperer简介 &#…...

Python内置对象
Python是一种强大的、动态类型的高级编程语言,其内置对象是构成程序的基础元素。Python的内置对象包括数字、字符串、列表、元组、字典、集合、布尔值和None等,每种对象都有特定的类型和用途。 01 什么是内置对象 这些对象是编程语言的基础构建块&…...

开源数据集 nuScenes 之 3D Occupancy Prediction
数据总体结构 Nuscenes 数据结构 可以看一下我的blog如何下载完整版 mmdetection3d ├── mmdet3d ├── tools ├── configs ├── data │ ├── nuscenes │ │ ├── maps │ │ ├── samples │ │ ├── sweeps │ │ ├── lidarseg (o…...

物联网竞赛板CubMx全部功能简洁配置汇总
目录 前言:1、按键&LED灯配置:2、OLED配置:3、继电器配置:4、LORA模块配置:5、矩阵模块:6、串口模块:7、RTC配置:8、ADC模块配置:9、温度传感器模块:后续…...

使用Redis做缓存的小案例
如果不了解Redis,可以查看本人博客:Redis入门 Redis基于内存,因此查询速度快,常常可以用来作为缓存使用,缓存就是我们在内存中开辟一段区域来存储我们查询比较频繁的数据,这样,我们在下一次查询…...

剧本杀小程序功能介绍
剧本杀功能介绍 剧本杀,一种融合了角色扮演与推理解谜的社交游戏,近年来在年轻人中越来越受欢迎。它不仅可以锻炼参与者的逻辑推理能力,还能增进朋友间的感情,提升团队协作能力。下面,我们将详细介绍剧本杀的核心功能…...
C#基础语法学习笔记(传智播客学习)
最近在学习C#开发知识,跟着传智播客的视频学习了一下,感觉还不错,整理一下学习笔记。 C#基础语法学习笔记 1.背景知识2.Visual Studio使用3.基础知识4.变量5.运算符与表达式6.程序调试7.判断结构8.循环结构9.常量、枚举类型10.结构体类型11.数…...
图论01-DFS和BFS(深搜和广搜邻接矩阵和邻接表/Java)
1.深度优先理论基础(dfs) dfs的两个关键操作 搜索方向,是认准一个方向搜,直到碰壁之后再换方向 换方向是撤销原路径,改为节点链接的下一个路径,回溯的过程。dfs解题模板 void dfs(参数) {if (终止条件) {存放结果;return;}for …...

【Python】Miniconda+Vscode+Jupyter 环境搭建
1.安装 Miniconda Conda 是一个开源的包管理和环境管理系统,可在 Windows、macOS 和 Linux 上运行,它可以快速安装、运行和更新软件包及其依赖项。使用 Conda,我们可以轻松在本地计算机上创建、保存、加载和切换不同的环境 Conda 分为 Anaco…...

Redis消息队列与thinkphp/queue操作
业务场景 场景一 用户完成注册后需要发送欢迎注册的问候邮件、同时后台要发送实时消息给用户对应的业务员有新的客户注册、最后将用户的注册数据通过接口推送到一个营销用的第三方平台。 遇到两个问题: 由于代码是串行方式,流程大致为:开…...

【Ubuntu】常用命令
一般操作 pwd(present working directory) 显示当前的工作目录/路径。 cd (change directory) 改变目录,用于输入需要前往的路径/目录。 有一些特殊命令也很常用 : 解释 前往同一级的另一个目录 cd ../directory name cd .. 表示进入上…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...