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; 【软考篇】中级软…

字母异位词分组[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你一个字符串数组&#xff0c;请你将字母异位词组合在一起。可以按任意顺序返回结果列表。字母异位词是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan"…

C# 泛型介绍

C# 中的泛型&#xff08;Generics&#xff09;是一种强类型参数化的特性&#xff0c;它允许你编写不具体指定数据类型的代码&#xff0c;而在实际使用时再指定具体的类型。泛型的引入使得代码更加灵活、可重用&#xff0c;并提高了类型安全性。 C#泛型基本用法 以下是一个简单…

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

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

交换机聚合配置 (H3C)

交换机聚合配置 &#xff08;H3C&#xff09; 聚合是什么如何配置聚合 聚合是什么 链路聚合是将两个或更多数据信道结合成一个单个的信道&#xff0c;该信道以一个单个的更高带宽的逻辑链路出现。一般用来连接一个或多个带宽需求大的设备&#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;免得有问题时候只能猜

LeetCode 面试题 16.22. 兰顿蚂蚁

文章目录 一、题目二、C# 题解 一、题目 一只蚂蚁坐在由白色和黑色方格构成的无限网格上。开始时&#xff0c;网格全白&#xff0c;蚂蚁面向右侧。每行走一步&#xff0c;蚂蚁执行以下操作。 (1) 如果在白色方格上&#xff0c;则翻转方格的颜色&#xff0c;向右(顺时针)转 90 度…

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

Oracle 中排序碰到 null 值如何处理

一、前言 Oracle 在 Order by 时缺省认为null是最大值&#xff0c;所以如果是ASC升序则排在最后&#xff0c;DESC降序则排在最前。 二、使用nulls first 或者nulls last 语法 nulls first 和 nulls last 是Oracle Order by支持的语法。 如果Order by 中指定了表达式Nulls f…

MySql跨库跨表触发器

一、跨库触发器的概念 跨库触发器是指能在一个数据库中创建的触发器&#xff0c;但触发器的操作涉及到其他数据库中的表。这种触发器的存在可以帮助我们实现一些复杂的业务逻辑&#xff0c;比如在一个数据库中的表更新时&#xff0c;自动更新另一个数据库中的相关表。 二、创建…

QT Creator 正则替换功能

原有的代码&#xff1a; cout<<"11"<<11232<<"333"<<4444; 现在希望添加一个条件编译,变成这样&#xff1a; #ifdef __DEBUG__ cout<<"11"<<11232<<"333"<<4444; #endif 但是一个…

669.修剪二叉树

原题链接:669.修剪二叉树 全代码&#xff1a; class Solution { public:TreeNode* trimBST(TreeNode* root, int low, int high) {if (root nullptr ) return nullptr;if (root->val < low) {TreeNode* right trimBST(root->right, low, high); // 寻找符合区间[l…

用PHP使用API接口获取虾皮商品详情

作为一名程序员&#xff0c;我们常常需要与各种API接口打交道&#xff0c;以获取我们需要的数据。本文将向您展示如何使用PHP编程语言与虾皮的API接口进行交互&#xff0c;以获取虾皮商品详情。 一、准备工作 在开始编写代码之前&#xff0c;确保您已经完成了以下准备工作&am…

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…