[Qt学习笔记]Qt实现自定义控件SwitchButton开关按钮

1、功能介绍

在项目UI中使用较多的打开/关闭的开关按钮,一般都是找图片去做效果,比如说如下的图像来表征打开或关闭。

图一.png图二.png图三.PNG

如果想要控件有打开/关闭的动画效果或比较好的视觉效果,这里就可以使用自定义控件,使用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

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

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

相关文章

数据库运行状况和性能监控工具

数据库监控是跟踪组织中数据库的可用性、安全性和性能的过程&#xff0c;它涉及通过跟踪各种关键指标来分析数据库的性能&#xff0c;确保数据库的正常运行并具有深入的可见性&#xff0c;并在出现潜在问题时触发即时警报&#xff0c;以采取主动措施来确保数据库的高可用性。 …

美团2024届秋招笔试第二场编程真题

要么是以0开头 要么以1开头 选择最小的答案累加 import java.util.Scanner; import java.util.*; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和…

OpenLayers基础教程——WebGLPoints图层样式的设置方法

1、前言 前一篇博客介绍了如何在OpenLayers中使用WebGLPoints加载海量数据点的方法&#xff0c;这篇博客就来介绍一下WebGLPoints图层的样式设置问题。 2、样式运算符 在VectorLayer图层中&#xff0c;我们只需要创建一个ol.style.Style对象即可&#xff0c;WebGLPoints则不…

【C++】基础:STL容器库

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍STL容器库。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新不迷路&#x1f95…

TransUNet论文笔记

论文&#xff1a;TransUNet&#xff1a;Transformers Make Strong Encoders for Medical Image Segmentation 目录 Abstract Introduction Related Works 各种研究试图将自注意机制集成到CNN中。 Transformer Method Transformer as Encoder 图像序列化 Patch Embed…

Java基础--128陷阱

问题引入 Integer a 123; Integer b 123; System.out.println(ab); 结果为true。 但是如果代码如下 Integer a 1230;Integer b 1230;System.out.println(ab); 这个的结果就是false。 问题解决 当Integer a 123时&#xff0c;其实他底层自动转换成了Integer a Inte…

ElasticSearch之数据建模

写在前面 本文看下es数据建模相关的内容。 1&#xff1a;什么是数据建模 数据建模是对真实数据的一种抽象&#xff0c;最终映射为计算机形式的表现。其包括如下三个阶段&#xff1a; 1&#xff1a;概念模型 2&#xff1a;逻辑模型 3&#xff1a;数据模型2&#xff1a;es数据…

Chrome浏览器修改网页内容

方法一&#xff1a;使用开发者工具 在Chrome浏览器中打开要修改的网页。按下F12键打开开发者工具。在开发者工具窗口中&#xff0c;找到“Elements”标签页。在“Elements”标签页中&#xff0c;找到要修改的网页元素。双击要修改的网页元素&#xff0c;即可进行编辑。 方法二…

CCDP.02.OS正确部署后的Dashboard摘图说明

前言 在部署成功OpenStack后&#xff0c;应该可以在浏览器打开Dashboard&#xff0c;并对计算资源&#xff08;这里主要是指VM&#xff09;进行管理&#xff0c;也可以在Dashboard上面查看OpenStack是否存在错误&#xff0c;下面&#xff0c;已针对检查的关键点&#xff0c;用红…

什么是Web应用防火墙,为什么这么重要

在一个每天都会出现新的网络攻击并出现的世界中&#xff0c;我们必须不断寻找和建立新的安全控制和保护机制。目前发现的最常见的网络安全威胁通常涉及数据泄露并且发生在应用程序级别&#xff0c;这就是许多系统无法抵御此类攻击的原因。因此&#xff0c;WEB 应用防火墙变的极…

牛客NC108 最大正方形【中等 动态规划 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/0058c4092cec44c2975e38223f10470e 思路 动态规划: 先初始化第一行和第一列。然后其他单元格依赖自己的上边&#xff0c;左边和左上角参考答案Java import java.util.*;public class Solution {/*** 代码中的类…

电动汽车NVH来源浅析

NVH性能作为汽车最重要的性能指标之一&#xff0c;直接决定着用户感知质量&#xff0c;提高产品的舒适性可以保证优良的市场竞争性。 电动汽车相对于传统燃油汽车会更加静谧&#xff0c;内燃机的工作原理是通过燃油在汽缸中燃烧产生的爆炸推动活塞运动&#xff0c;进而驱动汽车…

线上问题排查实例分析|Redis使用不同编码引发的问题

前言 某个周末的晚上突然收到一波耗时上升报警&#xff0c;仔细一看报警消息&#xff0c;原来是出现了慢查请求导致集群耗时大幅上升&#xff0c;此时业务同学也收到上游服务受影响报警。在处理问题过程中&#xff0c;运维同学发现 Redis 集群中只有部分实例出现 cpu 利用率上…

考研数学|《1800》《1000》《880》《660》怎么选?怎么刷?看这一篇就够了!

25考研选资料&#xff0c;主打一个听人劝&#xff0c;吃饱饭 有很多讲义&#xff0c;比如张宇30讲&#xff0c;汤家凤高等数学讲义&#xff0c;李永乐复习全书&#xff0c;武忠祥高等数学基础篇等等。 然后习题也有很多&#xff0c;比如1000题&#xff0c;1800题&#xff0c;…

ICCV 2023 Oral | 人类语言演化中学习最优图像颜色编码

人类的语言是一种对复杂世界的高度简洁的编码&#xff0c;特别是语言中颜色的概念&#xff0c;成功地将原本极大的色彩空间&#xff08;如256三次方真色彩空间&#xff09;压缩至5到10种颜色。受此启发&#xff0c;来自上海交大&#xff0c;日本理化学研究所&#xff0c;东京大…

vue2 中使用音频

vue2 中使用音频 在 template 页面 写入 audio 标签 <template><div><audio ref"moreAudio" :src"moreAudioSrc"></audio><audio ref"noAudio" :src"noAudioSrc"></audio></div> </t…

百能云板开启高品质铝基PCB线路板定制服务

铝基板是一种具有良好散热功能的金属基覆铜板&#xff0c;一般单面板由三层结构所组成&#xff0c;分别是电路层&#xff08;铜箔&#xff09;、绝缘层和金属基层。用于高端使用的也有设计为双面板&#xff0c;结构为电路层、绝缘层、铝基、绝缘层、电路层。极少数应用为多层板…

iOS开发进阶(九):OC混合开发嵌套H5应用并互相通信

文章目录 一、前言二、嵌套H5应用并实现双方通信2.1 WKWebView 与JS 原生交互2.1.1 H5页面嵌套2.1.2 常用代理方法2.1.3 OC调用JS方法2.1.4 JS调用OC方法 2.2 JSCore 实现原生与H5交互2.2.1 OC调用H5方法并传参2.2.2 H5给OC传参 2.3 UIWebView的基本用法2.3.1 H5页面嵌套2.3.2 …

Linux 理解文件系统、磁盘结构、软硬链接

目录 一、理解磁盘结构 1、磁盘的物理结构 2、硬件层面理解 3、磁盘的具体物理存储结构 4、进行逻辑抽象 5、磁盘文件的管理 6、创建新文件的过程 二、理解文件系统 1、文件的构成 2、为何选择4KB而非512字节作为基本单位? 3、文件系统的组成 数据块&#xff08;Data Blocks&a…

flask_restful规范返回值

使用方法 导入 flask_restful.marshal_with 装饰器 定义一个字典变量来指定需要返回的标准化字段&#xff0c;以及该字段的数据类型 在请求方法中&#xff0c;返回自定义对象的时候&#xff0c; flask_restful 会自动的读 取对象模型上的所有属性。 组装成一个符合标准化参…