[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.mfbz.cn/a/489352.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ primer 第十五章

1.OPP:概述 面向对象程序设计的核心思想是数据抽象、继承和动态绑定。 通过继承联系在一起的类构成一种层次关系&#xff0c;在层次关系的根部的是基类&#xff0c;基类下面的类是派生类 基类负责定义在层次关系中所有类共同拥有的成员&#xff0c;而每个派生类定义各自特有…

FFmpeg+mediamtx 实现将本地摄像头推送成RTSP流

文章目录 概要推流过程实现过程安装FFmpeg安装Mediamtx 启动推流 概要 FFmpegmediamtx实现将本地摄像头推送成RTSP流 FFmpeg 版本号为&#xff1a;N-114298-g97d2990ea6-20240321 mediamtx 版本号为&#xff1a;v1.6.0 推流过程 摄像头数据&#xff0c;经过ffmpeg的推流代码…

带手柄聚四氟乙烯烧杯方便省力好用

可定制各种规格形状四氟烧杯&#xff0c;也可以单独配盖子。 注&#xff1a;可配套我公司生产的防腐电热板、赶酸电热板后期赶酸使用。 产品特性 1.外观纯白色&#xff1b; 2.耐高低温&#xff1a;可使用温度-200℃&#xff5e;&#xff0b;250℃&#xff1b; 3.耐腐蚀&am…

基于SpringBoot+MyBatis+Vue的电商智慧仓储管理系统的设计与实现(源码+LW+部署+讲解)

前言 博主简介&#x1f468;&#x1f3fc;‍⚕️&#xff1a;国内某一线互联网公司全栈工程师&#x1f468;&#x1f3fc;‍&#x1f4bb;&#xff0c;业余自媒体创作者&#x1f4bb;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f4d5;&#x…

【直播预约】镭速邀您共赴2024年首场线上直播沙龙!

为了深入探讨智能制造数据安全交互的前沿趋势&#xff0c; 解锁数据安全在智能制造业的无限潜能&#xff0c; 镭速传输即将举办一场&#xff0c; 不容错过的2024首场线上直播沙龙&#xff01; 镭速传输&#xff0c;将在03月27日 14:30 在视频号进行直播 镭速助力行业数字化…

Jmeter使用教程,从安装到HTTP的压测全部实战教程解析,不学后悔系列

作为一名开发工程师&#xff0c;当我们接到需求的时候&#xff0c;一般就是分析需要&#xff0c;确定思路&#xff0c;编码&#xff0c;自测&#xff0c;然后就可以让测试人员去测试了。在自测这一步&#xff0c;作为开发人员&#xff0c;很多时候就是测一下业务流程是否正确&a…

IBM:《2023IBM年报》

2024年3月12日&#xff0c;IBM分享了《2023IBM年报》。 报告节选&#xff1a; 在本财年&#xff0c;IBM 的收入为 619 亿美元&#xff0c;按固定汇率计算增长 3%&#xff0c;自由现金流为 112 亿美元&#xff0c;同比增长 19 亿美元。我们经历了对新 watsonx 平台日益增长的需…

Python:基础语法

一、import与from.....import 有时候我们需要使用一些第三方库或包时&#xff0c;我们就需要通过import或from.....import导入模块。 # 导入库 import sys print("hello,world") 当我们自己写了些函数&#xff0c;在其他py文件&#xff0c;我们也可以通过from.....im…

Selenium 自动化 —— 浏览器窗口操作

更多内容请关注我的专栏&#xff1a; 入门和 Hello World 实例使用WebDriverManager自动下载驱动Selenium IDE录制、回放、导出Java源码 当用 Selenium 打开浏览器后&#xff0c;我们就可以通过 Selenium 对浏览器做各种操作&#xff0c;就像我们日常用鼠标和键盘操作浏览器一…

初学php反序列化

php中&#xff0c;序列化和反序列化是相对的两个过程&#xff0c;序列化是把变量或对象转化成字符串的过程 反序列化是把字符串转换为变量过着对象的过程 在php的反序列化中&#xff0c;存在类&#xff0c;当类被以特定的方式就会触发魔术方法&#xff0c;在实行序列化的过程…

element ui的下拉选择单选和多选

单选&#xff1a; html代码&#xff1a; <el-form-item label"指令分类: "><el-select v-model"cid" style"width:100%;" placeholder"请选择指令分类" clearable><el-option v-for"item in orderCidList"…

服务器中有g++,但是查询不到,Command ‘g++‘ not found

有gcc但是查询不到g&#xff0c;gcc版本为9.5.0 (base) zyICML:~$ g -V Command g not found, but can be installed with: apt install g Please ask your administrator. 突然就出现这个问题&#xff0c;导致detectron装不上&#xff0c;现在有时间了专门研究下怎么解决 这…

React Native 应用打包

引言 在将React Native应用上架至App Store时&#xff0c;除了通常的上架流程外&#xff0c;还需考虑一些额外的优化策略。本文将介绍如何通过配置App Transport Security、Release Scheme和启动屏优化技巧来提升React Native应用的上架质量和用户体验。 配置 App Transport…

❤ leetCode简易题1-两数之和、简易2--回文数判断、简易14-最长公共前缀

❤ leetCode简易题1-两数之和、简易题14- 最长公共前缀 1、简易1-两数之和 ① 题目要求 数字A B target&#xff0c;以target为求和结果&#xff0c;找出数组中符合的A、B数字下标。 第一次做的时候完全脑子一片蒙&#xff0c;随后认真看了看题目发现是发现找符合target和…

基于springboot+vue+Mysql的超市进销存系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

3.25C++

定义自己的命名空间&#xff0c;其中有string类型的变量&#xff0c;再定义两个函数&#xff0c;一个函数完成字符串的输入&#xff0c;一个函数完成求字符串长度&#xff0c;再定义一个全局函数完成对该字符串的反转 #include <iostream> #include <cstring> usi…

数据在内存的存储(2)【浮点数在内存的存储】

一.浮点数以什么形式存储在内存中 根据根据国际标准IEEE&#xff08;电气和电子工程协会&#xff09;754&#xff0c;任意一个二进制浮点数V都可以存储为这样的形式&#xff1a; V&#xff08;-1&#xff09;^S*M*2^E。 &#xff08;1&#xff09;&#xff08;-1&#xff09;^…

Unix环境高级编程-学习-08-自旋锁与屏障

目录 一、多线程相关文章链接 二、自由抒发 1、自旋锁 2、屏障 三、函数介绍 1、pthread_spin_init &#xff08;1&#xff09;声明 &#xff08;2&#xff09;作用 &#xff08;3&#xff09;参数 &#xff08;4&#xff09;返回值 &#xff08;5&#xff09;注意点 …

docker centos7安装jdk1.8(在线和离线方式)

目录 1.在线方式1.1.进入容器1.2.使用yum安装openjdk1.3.配置环境变量 2.离线方式2.1.下载jdk安装包2.2.解压2.3.配置环境变量 3.可能遇到的问题 1.在线方式 1.1.进入容器 1.2.使用yum安装openjdk # 安装JDK1.8 yum install java-1.8.0-openjdkjava -version1.3.配置环境变量…

RPA-财务对账邮件应用自动化(客户对账机器人)

《财务对账邮件应用自动化》&#xff0c;将会使用邮箱的SMTP服务&#xff0c;小北把资源包绑定在这篇博客了 Uibot (RPA设计软件)———机器人的小项目友友们可以参考小北的课前材料五博客~ (本博客中会有部分课程ppt截屏,如有侵权请及请及时与小北我取得联系~&#xff09; …
最新文章