Qt 之自定义控件(开关按钮)

news2024/11/27 5:35:41

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 关闭:false
    bool 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.coloradmin.cn/o/1207828.html

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

相关文章

Live800:高效工作,客服人必学的10种时间效率管理术

客服人员是企业与客户沟通的桥梁&#xff0c;需要在繁忙的工作环节中保持高效率。只有提高时间效率才能更好地服务客户&#xff0c;满足客户的需求&#xff0c;提升客户满意度。因此&#xff0c;客服人员需要掌握时间效率管理术来提高工作效率。 1、制定工作计划 在开始工作之…

C#中数组、ArrayList与List对象的区别及使用场景

在C#编程中&#xff0c;数组、ArrayList和List对象是常用的数据结构和容器。它们在存储和管理数据方面都有各自的特点和用途。本文将深入探讨这三者的区别&#xff0c;并通过实际的代码示例来说明它们的使用场景和优缺点。 目录 1.数组特点使用场景 2.ArrayList特点使用场景 3.…

eVTOL分布式电推进(DEP)动力测试系统

产品简介 分布式电推进&#xff08;DEP&#xff09;技术因其灵活多变的机械电气化设计&#xff0c;可以大大提升动力系统的安全性冗余&#xff0c;极大增强飞行过程中的可操控性&#xff0c;同时可以有效降低本机噪音&#xff0c;最大限度提升动力系统的能源使用效率等优势&am…

原生应用与hybrid app开发的流程区别

Hybrid App&#xff08;混合 App&#xff09;已经成为大家接触最为广泛的 App 形式&#xff0c;不管是我们用到的微信、支付宝还是淘宝、京东等大大小小的应用都非常热衷于Hybrid App 带来的研发效率提升和灵活性。 但我们正式进入到 hybrid App 的讨论前&#xff0c;有必要先…

C++:map和set的封装原理

文章目录 红黑树的封装map和set的封装红黑树迭代器的实现operator 和 -- 的实现的实现过程 迭代器的其他模块 整体实现 本篇写于红黑树模拟实现后&#xff0c;对map和set进行封装&#xff0c;模拟实现map和set内部的原理 首先&#xff0c;map和set的底层逻辑是红黑树&#xf…

【Apache Doris】审计日志插件 | 快速体验

【Apache Doris】审计日志插件 | 快速体验 一、 环境信息1.1 硬件信息1.2 软件信息 二、 审计日志插件介绍三、 快速 体验3.1 AuditLoader 配置3.1.1 下载 Audit Loader 插件3.1.2 解压安装包3.1.3 修改 plugin.conf 3.2 创建库表3.3 初始化3.4 验证 一、 环境信息 1.1 硬件信…

识别伪装IP的网络攻击方法

识别伪装IP的网络攻击可以通过以下几种方法&#xff1a; 观察IP地址的异常现象。攻击者在使用伪装IP地址进行攻击时&#xff0c;往往会存在一些异常现象&#xff0c;如突然出现的未知IP地址、异常的流量等。这些现象可能是攻击的痕迹&#xff0c;需要对此加以留意。 检查网络通…

私有云边界网络部署实践

业务背景 在私有云的业务场景中&#xff0c;常见的通信中包含了同VPC内虚机互访、不同VPC之间的虚机互访、VPC访问Underlay资源、VPC访问Internet资源、VPC提供服务&#xff0c;被Internet访问、VPC与专线网络之间互访等&#xff1b;实际应用中&#xff0c;大多数云业务通信场…

车间安灯呼叫看板的功能与优势介绍

现在的工厂车间的管理变得越来越复杂&#xff0c;生产过程中可能会出现各种问题&#xff0c;如设备故障、物料短缺、工人伤病等。为了提高生产效率、优化生产管理&#xff0c;许多工厂引入了车间安灯呼叫看板系统。本文将介绍车间安灯呼叫看板的功能与优势。 一、功能介绍 1. 实…

[单片机课程设计报告汇总] 单片机设计报告常用硬件元器件描述

[单片机课程设计必看] 单片机设计报告常用描述 硬件设计 AT89C51最小系统 AT89C51是美国ATMEL公司生产的低电压&#xff0c;高性能CMOS16位单片机&#xff0c;片内含4k bytes的可反复擦写的只读程序存储器和128 bytes的随机存取数据存储器&#xff0c;期间采用ATMEL公司的高…

python matlplotlib/seaborn 绘制曲线的平均值标准差阴影图

1. seaborn 旧版本(0.8.1)中使用tsplot&#xff0c;新版本中使用lineplot 直线代表均值&#xff0c;阴影代表meanstd&#xff08;带有置信区间&#xff0c;参数ci&#xff09; import seaborn as sns import matplotlib.pyplot as plt import numpy as np import pandas as p…

攻略 | 参与Moonbeam Ignite Ecosystem Tour

Moonbeam联合Moonwell和Beamswap一起举办社区链上活动&#xff0c;旨在让社区用户通过任务来探索Moonbeam、Moonwell、Beamswap平台。在了解如何使用的同时&#xff0c;参与任务挑战还有机会分得 1700 USDC 奖池 &#x1f381; 的奖励&#xff01;我已经完成全部任务&#xff0…

AR人脸道具SDK,打造极致用户体验

为了满足企业在AR领域的应用需求&#xff0c;美摄科技推出了一款领先的AR人脸道具SDK&#xff0c;旨在帮助企业快速、高效地开发出具有丰富玩法体验的AR应用&#xff0c;从而提升企业的竞争力和市场份额。 一、丰富的AR人脸道具&#xff0c;满足多样化需求 美摄科技AR人脸道具…

怎么阅读芯片源代码(rtl)

一个rtl可以是这样的&#xff1a; 经常大家习惯于算法和数据结构。对于设计的部分&#xff0c;落实不一定多。 另外一个rtl也可以是这样的&#xff1a; 所以从不同的层面来讲&#xff0c;一个Rtl有不同的表述。 首先大概把所有的部分浏览一遍&#xff0c;看看有些什么。 其次…

喜报不断!箱讯平台获评2023年上海市促进现代航运服务业创新示范项目

近期&#xff0c;可谓捷报频传&#xff01;在箱讯科技子公司苏州箱讯获评苏州市软件和信息服务业 “头雁”培育企业没过多久&#xff0c;就又迎来好消息&#xff01; 日前&#xff0c;上海市交通委发布“2023年上海市促进现代航运服务业创新项目”评选结果&#xff0c;箱讯An…

抖音小程序开发全攻略:如何规划项目和选择合适的开发团队

在数字化时代&#xff0c;抖音小程序成为企业推广和服务的重要渠道。本文将为您提供抖音小程序开发的全面攻略&#xff0c;重点介绍如何规划项目和选择合适的开发团队&#xff0c;并附有一些关键的技术代码示例。 1. 项目规划 在开始抖音小程序开发之前&#xff0c;详细的项…

能够导出源代码的低代码平台有哪些?

目录 一、源码的优势 &#xff08;1&#xff09;定制性需求&#xff1a; &#xff08;2&#xff09;适应未来需求变化&#xff1a; &#xff08;3&#xff09;安全和可靠性&#xff1a; &#xff08;4&#xff09;高级功能和集成&#xff1a; 二、支持源代码的厂商 目前国内大多…

Javaweb开发 利用servlet+jsp+jdbc+tomcat数据库实现登录功能

前言&#xff1a;很久没更新了&#xff0c;今天给大家分享一个Java web的小案例&#xff0c;是一个登录页面&#xff0c;利用Login控制类和JDBC连接数据库&#xff0c;并判断用户名密码是否正确&#xff0c;项目最终部署在Tomcat上。 先看效果 正文 一、前期工作 1.首先我们…

Netty+SpringBoot 打造一个 TCP 长连接通讯方案

项目背景 最近公司某物联网项目需要使用socket长连接进行消息通讯&#xff0c;捣鼓了一版代码上线&#xff0c;结果BUG不断&#xff0c;本猿寝食难安&#xff0c;于是求助度娘&#xff0c;数日未眠项目终于平稳运行了&#xff0c;本着开源共享的精神&#xff0c;本猿把项目代码…

Excel-快速将公式运用到一整列

先在该列的第一个单元格里写好公式&#xff0c;然后单击该单元格 在图中标示的地方输入我们需要填充的单元格区域 同时按住Ctrl和Enter键&#xff0c;这时需要填充的单元格区域就都被选中了 然后单击一下图中公式的后面&#xff0c;再次按下Ctrl和Enter键&#xff0c;这样就完…