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 关闭:falsebool 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.mzph.cn/news/144848.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网工内推 | 国企、上市公司售前,CISP/CISSP认证,最高18K*14薪

01 中电福富信息科技有限公司 招聘岗位&#xff1a;售前工程师&#xff08;安全&#xff09; 职责描述&#xff1a; 1、对行业、用户需求、竞争对手等方面提出分析报告&#xff0c;为公司市场方向、产品研发和软件开发提供建议&#xff1b; 2、负责项目售前跟踪、技术支持、需…

【软考篇】中级软件设计师 第四部分(三)

中级软件设计师 第四部分&#xff08;三&#xff09; 三十四. 结构化开发方法34.1 内聚34.2 耦合 三十五. 测试基础知识三十六. 面向对象36.1 UML图36.2 设计模式36.3 数据流图 读前须知&#xff1a; 【软考篇】中级软件设计师 学前须知 上一章节&#xff1a; 【软考篇】中级软…

【全网首发】【Python】Python控制parrot ARDrone 2.0无人机

&#x1f389;欢迎来到Python专栏~Python控制parrot ARDrone 2.0无人机 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;Python学习专栏 文章作者技术和水平有限&#xff0c;如果文中出现错误…

基于IDEA创建Maven工程及注意事项

Java全能学习面试指南&#xff1a;https://javaxiaobear.cn 1. 概念梳理Maven工程的GAVP Maven工程相对之前的项目&#xff0c;多出一组gavp属性&#xff0c;gav需要我们在创建项目的时候指定&#xff0c;p有默认值&#xff0c;我们先行了解下这组属性的含义&#xff1a; Ma…

java的Exception.getMessage为null

之前捕获异常后调用异常的getMessage写日志&#xff0c;日志写的竟然是null&#xff0c;不可思议。发现要调用异常的getCause().getMessage()才能得到异常信息 刻意把密码改错&#xff0c;让异常直达界面&#xff0c;免得有问题时候只能猜

Linux Traefik工具Dashboard结合内网穿透实现远程访问

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件&#xff0c;能轻易的部署微服务。它支持多种后端 (D…

区域入侵AI算法如何应用在工地场景,保卫工地施工安全?

在工地、厂区等施工场所&#xff0c;安全保障是必不可少的&#xff0c;特别是在人工智能技术日益成熟的今天&#xff0c;如何利用旭帆科技AI智能视频中的区域入侵算法助力智慧工地、保障工地安全呢&#xff1f; 1、建筑物周界安全 TSINGSEE青犀区域入侵算法可以用于监控建筑物…

M系列 Mac安装配置Homebrew

目录 首先&#xff0c;验证电脑是否安装了Homebrew 1、打开终端输入以下指令&#xff1a; 2、如图所示&#xff0c;该电脑没有安装Homebrew &#xff0c;下面我们安装Homebrew 一、官网下载 &#xff08;不建议&#xff09; 1、我们打开官网&#xff1a;https://brew.sh/ …

C++ 模板 (一)

1. 泛型编程 如何实现一个通用的交换函数呢&#xff1f; void Swap(int& left, int& right) { int temp left; left right; right temp; } void Swap(double& left, double& right) { double temp left; left right; right temp; } void Swap(char&…

1116中信笔试

1116中信笔试 int, Integer的区别&#xff0c;相等如何判断结果Java的异常处理数据库的事务操作Redis的基本数据类型问了HashMap底层实现TCP协议MySQL的隔离级别创建线程的几种方式双亲委派机制 &#xff0c;它的优点linux命令&#xff08;查看线程&#xff09; java和数据库ha…

【LeetCode刷题-滑动窗口】--567.字符串的排列

567.字符串的排列 方法&#xff1a;滑动窗口 由于排列不会改变字符串中每个字符的个数&#xff0c;所以只有当两个字符串每个字符的个数均相等时&#xff0c;才是另一个字符串的排列 根据这一性质&#xff0c;记s1的长度为n&#xff0c;遍历s2中的每个长度为n的子串&#xff…

汇川伺服【选型目录】

sv680旗舰&#xff1a; 编码器位数&#xff1a;26bit 电机额定转速&#xff1a;3000r【3k】圈脉冲&#xff1a; sv670标准&#xff1a; 编码器位数&#xff1a;23bit【台达B3:23bit&#xff0c;台达A2&#xff1a;bit】 电机额定转速&#xff1a;3000r【3k】圈脉冲&#xff1…

【算法|动态规划 | 区间dp No.2】AcWing 1068.环形石子合并

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【AcWing算法提高学习专栏】【手撕算法系列专栏】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&a…

css实现鼠标悬停时元素的显示与隐藏

css实现鼠标悬停时元素的显示与隐藏 跟着B站黑马学习小兔鲜项目&#xff0c;有个点记录一下 就是当鼠标悬浮在商品列表上时&#xff0c;列表中的商品会显示出来&#xff0c;离开时&#xff0c;商品隐藏&#xff0c;如下&#xff1a; 感觉这个功能经常会遇到&#xff0c;但一直…

思考如何完成一个审批流

思考如何完成一个审批流 这篇文章&#xff0c;可能没有太多的干货&#xff0c;只是对于自己做过项目的一个反思与整理&#xff0c;同时&#xff0c;让这篇文章暴露在公共视野&#xff0c;虚心接受批评指导&#xff0c;向各位前辈同仁进行学习。 如果此文又不当之处&#xff0c;…

数据库管理-第116期 Oracle Exadata 06-ESS-下(202301114)

数据库管理-第116期 Oracle Exadata 06-ESS-下&#xff08;202301114&#xff09; 距离上一次正儿八经的技术分享又过了整整一周了&#xff0c;距离上一期Exadata专题文章也过了11天了&#xff0c;今天一鼓作气把ESS写完&#xff0c;毕竟明天又要飞北京了。 1 Smart Scan 其…

uniapp大概是怎么个开发法(前端)

写在前面&#xff0c;博主是个在北京打拼的码农&#xff0c;从事前端工作5年了&#xff0c;做过十多个大大小小不同类型的项目&#xff0c;最近心血来潮在这儿写点东西&#xff0c;欢迎大家多多指教。 对于文章中出现的任何错误请大家批评指出&#xff0c;一定及时修改。有任何…

如何实时提取微信群收到的二维码图片?

10-4 在有些工作中&#xff0c;需要实时提取在微信中收到的二维码图片&#xff0c;比如微信里有一百个群&#xff0c;怎么才能知道这些群里发了二维码出来&#xff0c;要实现这样的功能&#xff0c;微信本身并不提供&#xff0c;但是可以通过一些其它技巧完成。 大概的原理是…

鸿蒙原生应用开发-DevEco Studio中HarmonyOS与OpenHarmony项目的切换

一、找到该目录 二、修改操作系统类型 三、分别进行开发&#xff0c;一些常规的应用功能实现后&#xff0c;相互切换后都可以正常运行的。前期OpenHarmony项目如果连接开发板比较困难的化&#xff0c;开发完成后&#xff0c;切换成为HarmonyOS后就可以比较详细地看看效果了。

企业微信H5开发遇到的坑

企业微信官方推荐wx.agentConfig引用<script src"https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>是没有效果的 必须引用以下代码才有效果&#xff0c;这也是我看了社区的回答才有所收获&#xff0c;是一个坑 且VUE引用在线的…