[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 .. 表示进入上…...
Linux Socket编程进阶:send()函数flags参数全解析,从MSG_DONTWAIT到MSG_MORE的实战避坑指南
Linux Socket编程进阶:send()函数flags参数全解析与实战避坑指南 在网络编程的世界里,send()函数就像是一位沉默的信使,而它的flags参数则是这位信使的"行为模式开关"。今天,我们不谈基础,直接深入探讨如何…...
别再东拼西凑了!我为你整理了一份超全的嵌入式开发知识图谱(含学习路线与避坑指南)
嵌入式开发者的终极成长指南:从菜鸟到架构师的系统化进阶路线 当我在2015年第一次接触STM32开发板时,面对满屏的寄存器配置和晦涩的数据手册,曾一度怀疑自己是否选错了职业方向。八年后的今天,当我带领团队完成第五代工业控制器开…...
Dify 2026微调方法论深度拆解(2026 Q1官方未公开的梯度压缩协议与显存优化参数)
第一章:Dify 2026微调方法论的范式演进与核心定位Dify 2026标志着大模型应用开发范式的结构性跃迁——从“提示工程主导”的轻量适配,转向“数据-架构-评估”三位一体的闭环微调范式。其核心定位已超越传统LoRA或QLoRA的参数高效微调工具集,演…...
别再死记硬背了!用PyTorch亲手画一画CNN的特征图,秒懂它在‘看’什么
用PyTorch可视化CNN特征图:揭开神经网络的神秘面纱 当你第一次听说卷积神经网络(CNN)能识别猫狗时,是否也好奇过它究竟"看到"了什么?那些抽象的数字矩阵背后,隐藏着怎样的视觉逻辑?今…...
Multisim仿真 vs 洞洞板实战:我的双路稳压电源项目翻车与复盘全记录
Multisim仿真与洞洞板实战:双路稳压电源的翻车启示录 仿真软件里完美的电路设计,在现实中却频频翻车——这几乎是每个硬件工程师的必经之路。去年冬天,我也经历了这样一场"理想很丰满,现实很骨感"的双路稳压电源项目。当…...
从科研到报告:MATLAB bar函数实战避坑指南(颜色、标签、分类数据一篇搞定)
MATLAB条形图实战指南:避开颜色、标签与分类数据的那些坑 科研报告中的图表质量直接影响读者对数据的理解效率。作为MATLAB中最常用的可视化工具之一,bar函数看似简单,却暗藏诸多细节陷阱——从颜色配置失误到标签错位,从分类顺序…...
从浏览器到服务器:图解HttpServletResponse如何操控文件流(原理+实践)
HTTP文件流传输的底层机制与高效实践 当你在浏览器中点击一个下载链接时,看似简单的操作背后隐藏着一系列精妙的协议交互和数据流动过程。作为开发者,理解HttpServletResponse如何操控文件流不仅能够优化文件传输性能,还能解决实际开发中的各…...
谷歌监控-从Linux延申到MySQL - 详解
从Linux到MySQL:构建面向实战的四层漏斗监控体系 引言:为什么监控需要“漏斗式”思维 2025年,Gartner在《Monitoring and Observability Hype Cycle》中指出,随着数字化基础设施复杂度不断提升,单纯的“监控”已远远不…...
黑苹果安装终极指南:10个步骤打造完美macOS体验
黑苹果安装终极指南:10个步骤打造完美macOS体验 【免费下载链接】Hackintosh Hackintosh long-term maintenance model EFI and installation tutorial 项目地址: https://gitcode.com/gh_mirrors/ha/Hackintosh 还在为苹果电脑的高昂价格望而却步吗…...
Session Startup:中描述的md文件是代码读取,还是 AI 操作?
Session Startup:文件是代码读取,还是 AI 操作? 核心结论:代码已经读取,Session Startup 只是声明。 🎯 直接答案 代码已经读取,Session Startup 只是声明。 📊 对比分析 项目 实际情况 谁读取文件? 代码,不是 AI 何时读取? 在 AI 启动前,系统构建 prompt 时 Se…...



