QT 实现按钮多样化

1.界面实现效果

以下是具体的项目需要用到的效果展示,可以根据需要,实例化想要的按钮。
在这里插入图片描述

2.简介

原理:使用Qt的QPropertyAnimation动画类,这里简单来说就是切换两个按钮样式。
请看以下结构体:

#define MAX_LINE_COUNT 3

struct PurelinStatus
{
    QSizeF bgSize;                       // 背景尺寸
    double bgRadius = 0;                 // 背景圆角
    QColor bgColor = Qt::white;          // 背景颜色
    int useLine = 0;                     // 使用的线条数量
    QLineF linePoss[MAX_LINE_COUNT];     // 各线条位置
    QPointF lineHide[MAX_LINE_COUNT];     // 默认消失的位置
    QColor lineColors[MAX_LINE_COUNT];   // 各线条颜色

    PurelinStatus(int useLine = 0) : useLine(useLine)
    {
        for (int i = useLine; i < MAX_LINE_COUNT; i++)
        {
            linePoss[i] = QLineF(0, 0, 0, 0);
            lineColors[i] = Qt::transparent;
        }
    }
};

根据线条的数量、颜色、背景颜色、线条消失的位置等属性,在paintEvent中进行绘制图形。

void PurelinButton::paintEvent(QPaintEvent *)
{
    // 背景位置
    QSizeF bgSize = currentStatus.bgSize;
    if (bgSize.isEmpty())
        bgSize = this->size();
    double left = (this->width() - bgSize.width()) / 2;
    double top = (this->height() - bgSize.height()) / 2;
    QRectF rect(left, top, bgSize.width(), bgSize.height());

    // 绘制背景
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    QPainterPath path;
    path.addRoundedRect(rect, currentStatus.bgRadius, currentStatus.bgRadius);
    painter.fillPath(path, currentStatus.bgColor);

    // 绘制前景
    const double penWidth = 3.0;
    for (int i = 0; i < currentStatus.useLine; i++)
    {
        const QLineF& line = currentStatus.linePoss[i];
        if ((line.length() < 1e-4))
            continue;

        painter.setPen(QPen(currentStatus.lineColors[i], penWidth, Qt::SolidLine, Qt::RoundCap));
        painter.drawLine(currentStatus.linePoss[i]);
    }
}

3.Button类实现

#ifndef PURELINBUTTON_H
#define PURELINBUTTON_H

#include <QPushButton>
#include <QList>

#define MAX_LINE_COUNT 3

struct PurelinStatus
{
    QSizeF bgSize;                       // 背景尺寸
    double bgRadius = 0;                 // 背景圆角
    QColor bgColor = Qt::white;          // 背景颜色
    int useLine = 0;                     // 使用的线条数量
    QLineF linePoss[MAX_LINE_COUNT];     // 各线条位置
    QPointF lineHide[MAX_LINE_COUNT];     // 默认消失的位置
    QColor lineColors[MAX_LINE_COUNT];   // 各线条颜色

    PurelinStatus(int useLine = 0) : useLine(useLine)
    {
        for (int i = useLine; i < MAX_LINE_COUNT; i++)
        {
            linePoss[i] = QLineF(0, 0, 0, 0);
            lineColors[i] = Qt::transparent;
        }
    }
};

class PurelinButton : public QPushButton
{
    Q_OBJECT
public:
    PurelinButton(QWidget* parent = nullptr);

    const PurelinStatus& getCurrentStatus() const;
    void setCurrentStatus(PurelinStatus status);

    /// 加载显示状态
    void load(PurelinStatus status);

protected:
    void paintEvent(QPaintEvent *) override;

private slots:
    virtual void aniProgChanged(const QVariant& var);
    void aniProgFinished();

private:
    bool animating = false;
    double animationProg = 0;

    PurelinStatus currentStatus;
    PurelinStatus prevStatus;
    PurelinStatus nextStatus;
};

#endif // PURELINBUTTON_H

#include "purelinbutton.h"
#include <QPainter>
#include <QPainterPath>
#include <QDebug>
#include <QPropertyAnimation>

PurelinButton::PurelinButton(QWidget *parent) : QPushButton(parent)
{

}

const PurelinStatus &PurelinButton::getCurrentStatus() const
{
    return currentStatus;
}

void PurelinButton::setCurrentStatus(PurelinStatus status)
{
    this->currentStatus = status;
}

void PurelinButton::load(PurelinStatus status)
{
    prevStatus = currentStatus;
    nextStatus = status;

    if (prevStatus.useLine < nextStatus.useLine)
    {
        for (int i = prevStatus.useLine; i < nextStatus.useLine; i++)
        {
            prevStatus.linePoss[i] = QLineF(nextStatus.lineHide[i], nextStatus.lineHide[i]);
            prevStatus.lineColors[i] = nextStatus.lineColors[i];
        }
    }
    else
    {
        for (int i = nextStatus.useLine; i < prevStatus.useLine; i++)
        {
            nextStatus.linePoss[i] = QLineF(prevStatus.lineHide[i], prevStatus.lineHide[i]);
            nextStatus.lineColors[i] = prevStatus.lineColors[i];
        }
    }
    if (prevStatus.bgSize.isEmpty())
        prevStatus.bgSize = this->size();
    if (nextStatus.bgSize.isEmpty())
        nextStatus.bgSize = this->size();

    QPropertyAnimation* ani = new QPropertyAnimation(this, "");
    ani->setStartValue(0.0);
    ani->setEndValue(1.0);
    ani->setDuration(500);
    ani->setEasingCurve(QEasingCurve::OutQuad);
    connect(ani, &QPropertyAnimation::valueChanged, this, &PurelinButton::aniProgChanged);
    connect(ani, SIGNAL(finished()), ani, SLOT(deleteLater()));
    connect(ani, SIGNAL(finished()), this, SLOT(aniProgFinished()));
    ani->start();
}

void PurelinButton::paintEvent(QPaintEvent *)
{
    // 背景位置
    QSizeF bgSize = currentStatus.bgSize;
    if (bgSize.isEmpty())
        bgSize = this->size();
    double left = (this->width() - bgSize.width()) / 2;
    double top = (this->height() - bgSize.height()) / 2;
    QRectF rect(left, top, bgSize.width(), bgSize.height());

    // 绘制背景
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    QPainterPath path;
    path.addRoundedRect(rect, currentStatus.bgRadius, currentStatus.bgRadius);
    painter.fillPath(path, currentStatus.bgColor);

    // 绘制前景
    const double penWidth = 3.0;
    for (int i = 0; i < currentStatus.useLine; i++)
    {
        const QLineF& line = currentStatus.linePoss[i];
        if ((line.length() < 1e-4))
            continue;

        painter.setPen(QPen(currentStatus.lineColors[i], penWidth, Qt::SolidLine, Qt::RoundCap));
        painter.drawLine(currentStatus.linePoss[i]);
    }
}


void PurelinButton::aniProgChanged(const QVariant &var)
{
    // 可以重新这个方法,自定义尺寸
    // 比如,按照控件的百分比大小进行调整,而不是像素数值
    double prog = var.toDouble();

    currentStatus.bgRadius = prevStatus.bgRadius + prog * (nextStatus.bgRadius - prevStatus.bgRadius);
    currentStatus.bgSize = QSizeF(prevStatus.bgSize.width() + prog * (nextStatus.bgSize.width() - prevStatus.bgSize.width()),
                                 prevStatus.bgSize.height() + prog * (nextStatus.bgSize.height() - prevStatus.bgSize.height()));
    currentStatus.bgColor.setRgbF(
                prevStatus.bgColor.redF() + prog * (nextStatus.bgColor.redF() - prevStatus.bgColor.redF()),
                prevStatus.bgColor.greenF() + prog * (nextStatus.bgColor.greenF() - prevStatus.bgColor.greenF()),
                prevStatus.bgColor.blueF() + prog * (nextStatus.bgColor.blueF() - prevStatus.bgColor.blueF()),
                prevStatus.bgColor.alphaF() + prog * (nextStatus.bgColor.alphaF() - prevStatus.bgColor.alphaF()));
    int lineCount = qMax(prevStatus.useLine, nextStatus.useLine);
    currentStatus.useLine = lineCount;
    for (int i = 0; i < lineCount; i++)
    {
        currentStatus.linePoss[i].setLine(
                    prevStatus.linePoss[i].x1() + prog * (nextStatus.linePoss[i].x1() - prevStatus.linePoss[i].x1()),
                    prevStatus.linePoss[i].y1() + prog * (nextStatus.linePoss[i].y1() - prevStatus.linePoss[i].y1()),
                    prevStatus.linePoss[i].x2() + prog * (nextStatus.linePoss[i].x2() - prevStatus.linePoss[i].x2()),
                    prevStatus.linePoss[i].y2() + prog * (nextStatus.linePoss[i].y2() - prevStatus.linePoss[i].y2()));

        currentStatus.lineColors[i].setRgbF(
                    prevStatus.lineColors[i].redF() + prog * (nextStatus.lineColors[i].redF() - prevStatus.lineColors[i].redF()),
                    prevStatus.lineColors[i].greenF() + prog * (nextStatus.lineColors[i].greenF() - prevStatus.lineColors[i].greenF()),
                    prevStatus.lineColors[i].blueF() + prog * (nextStatus.lineColors[i].blueF() - prevStatus.lineColors[i].blueF()),
                    prevStatus.lineColors[i].alphaF() + prog * (nextStatus.lineColors[i].alphaF() - prevStatus.lineColors[i].alphaF()));
    }

    update();
}

void PurelinButton::aniProgFinished()
{
    currentStatus = nextStatus;
    animating = false;
}

4.使用

MainWindow界面上拖动一个QPushButton按钮,将这个按钮提升为我们自定义的类。
在这里插入图片描述

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QGraphicsDropShadowEffect>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this);
    shadow->setOffset(3, 5);
    shadow->setColor(QColor("#44888888"));
    shadow->setBlurRadius(20);
    ui->pushButton->setGraphicsEffect(shadow);
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_pushButton_clicked()
{
    const int totalCount = 8;
    static int index = -1;
    int dx = 0;

    // -
    PurelinStatus status[totalCount];
    int i = 0;
    status[i].bgSize = QSize(100, 60);
    status[i].bgColor = Qt::white;
    status[i].bgRadius = 30;
    status[i].useLine = 1;
    status[i].linePoss[0] = QLineF(35, 50, 65, 50);
    status[i].lineHide[0] = QPointF(50, 50);
    status[i].lineColors[0] =  QColor("#ed657d");

    // +
    i++;
    status[i].bgSize = QSize(-1, -1);
    status[i].bgColor = Qt::white;
    status[i].bgRadius = 30;
    status[i].useLine = 2;
    status[i].linePoss[0] = QLineF(35, 50, 65, 50);
    status[i].linePoss[1] = QLineF(50, 65, 50, 35);
    status[i].lineHide[0] = QPointF(50, 50);
    status[i].lineHide[1] = QPointF(50, 50);
    status[i].lineColors[0] = QColor("#5baaf8");
    status[i].lineColors[1] = QColor("#5baaf8");

    // x
    i++;
    status[i].bgSize = QSize(-1, -1);
    status[i].bgColor = Qt::white;
    status[i].bgRadius = 50;
    status[i].useLine = 2;
    status[i].linePoss[0] = QLineF(40, 40, 60, 60);
    status[i].linePoss[1] = QLineF(40, 60, 60, 40);
    status[i].lineHide[0] = QPointF(50, 50);
    status[i].lineHide[1] = QPointF(50, 50);
    status[i].lineColors[0] = QColor("#b9b9b9");
    status[i].lineColors[1] = QColor("#b9b9b9");

    // √
    i++;
    dx = -2;
    status[i].bgSize = QSize(-1, -1);
    status[i].bgColor = Qt::white;
    status[i].bgRadius = 50;
    status[i].useLine = 2;
    status[i].linePoss[0] = QLineF(40 + dx, 50, 50 + dx, 60);
    status[i].linePoss[1] = QLineF(50 + dx, 60, 70 + dx, 40);
    status[i].lineHide[0] = QPointF(50 + dx, 50);
    status[i].lineHide[1] = QPointF(50 + dx, 50);
    status[i].lineColors[0] = QColor("#59ce84");
    status[i].lineColors[1] = QColor("#59ce84");

    // <
    i++;
    dx = -4;
    status[i].bgSize = QSize(-1, -1);
    status[i].bgColor = Qt::white;
    status[i].bgRadius = 50;
    status[i].useLine = 2;
    status[i].linePoss[0] = QLineF(42 + dx, 50, 58 + dx, 65);
    status[i].linePoss[1] = QLineF(42 + dx, 50, 58 + dx, 35);
    status[i].lineHide[0] = QPointF(50, 50);
    status[i].lineHide[1] = QPointF(50, 50);
    status[i].lineColors[0] = QColor("#4b6fea");
    status[i].lineColors[1] = QColor("#4b6fea");

    // =
    i++;
    status[i].bgSize = QSize(100, 60);
    status[i].bgColor = Qt::white;
    status[i].bgRadius = 30;
    status[i].useLine = 2;
    status[i].linePoss[0] = QLineF(35, 55, 65, 55);
    status[i].linePoss[1] = QLineF(35, 45, 65, 45);
    status[i].lineHide[0] = QPointF(50, 55);
    status[i].lineHide[1] = QPointF(50, 45);
    status[i].lineColors[0] = QColor("#eda244");
    status[i].lineColors[1] = QColor("#eda244");

    // 三
    i++;
    status[i].bgSize = QSize(-1, -1);
    status[i].bgColor = Qt::white;
    status[i].bgRadius = 20;
    status[i].useLine = 3;
    status[i].linePoss[1] = QLineF(34, 37, 66, 37);
    status[i].linePoss[0] = QLineF(40, 50, 60, 50);
    status[i].linePoss[2] = QLineF(46, 63, 54, 63);
    status[i].lineHide[1] = QPointF(50, 37);
    status[i].lineHide[0] = QPointF(50, 50);
    status[i].lineHide[2] = QPointF(50, 63);
    status[i].lineColors[1] = QColor("#7248e3");
    status[i].lineColors[0] = QColor("#7248e3");
    status[i].lineColors[2] = QColor("#7248e3");

    // ≡
    i++;
    status[i].bgSize = QSize(-1, -1);
    status[i].bgColor = Qt::white;
    status[i].bgRadius = 20;
    status[i].useLine = 3;
    status[i].linePoss[1] = QLineF(35, 37, 65, 37);
    status[i].linePoss[0] = QLineF(35, 50, 55, 50);
    status[i].linePoss[2] = QLineF(35, 63, 60, 63);
    status[i].lineHide[1] = QPointF(35, 37);
    status[i].lineHide[0] = QPointF(35, 50);
    status[i].lineHide[2] = QPointF(35, 63);
    status[i].lineColors[1] = QColor("#424649");
    status[i].lineColors[0] = QColor("#424649");
    status[i].lineColors[2] = QColor("#424649");


    if (++index >= totalCount)
        index = 0;
    ui->pushButton->load(status[index]);
}

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

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

相关文章

系统架构设计师⑧:软件工程-软件开发方法与模型

系统架构设计师⑧&#xff1a;软件工程-软件开发方法与模型 软件开发方法 常用的软件开发方法主要分为3类&#xff1a; 结构化法&#xff08;比如C语言开发-面向过程&#xff09;&#xff0c; 面向对象法&#xff08;比如C或者JAVA开发-面向对象&#xff09;&#xff0c; 面向…

Nodejs和C#使用ECDH算法交换秘钥

转载于&#xff1a;https://bkssl.com/document/nodejs-csharp-ecdh.html nodejs的ECDH算法在进行computeSecret的时候不会自动进行HASH运算&#xff0c;但C#的ECDH算法必须指定HASH算法。 两边算法必须使用相同的椭圆曲线和Hash算法&#xff0c;例如下面用例都是用的SHA256。…

Matlab|用于平抑可再生能源功率波动的储能电站建模及评价

目录 主要内容 模型研究 1.目标函数 2.约束条件 部分代码 结果一览 1.储能平抑风电功率 2.储能平抑风电和光伏功率 下载链接 主要内容 程序参考文献《用于平抑可再生能源功率波动的储能电站建模及评价》&#xff0c;针对风电和光伏分布式能源出力波动的问…

题目:连续子序列

解题思路&#xff1a; 首先&#xff0c;不能使用暴力枚举&#xff0c;时间为O(n2)&#xff0c;超时。以下为正确做法&#xff1a; 假设找到一段区间&#xff08;其和>m&#xff09;&#xff0c;如上图黄色部分&#xff0c;那么该区间加上i后面的元素形成的新区间和都>m&a…

opencv学习:CascadeClassifier和detectMultiScale算法进行人脸识别

CascadeClassifier CascadeClassifier 是 OpenCV 提供的一个用于对象检测的类&#xff0c;它基于Haar特征和AdaBoost算法。它能够识别图像中的特定对象&#xff0c;比如人脸、眼睛、微笑等。CascadeClassifier 需要一个预训练的XML分类器文件&#xff0c;该文件包含了用于检测…

CodeActAgent :Executable Code Actions Elicit Better LLM Agents解读

论文地址 https://arxiv.org/pdf/2402.01030.pdf 项目地址 https://github.com/svjack/CodeActAgent-Gradio/blob/main/README.md 代码智能体的优势 选择代码智能体有以下几个关键原因&#xff0c;它们相较于使用类似JSON的字典输出具有显著优势&#xff1a; 1. 代码的高…

Spring Boot 应用开发:入门与实战

Spring Boot 应用开发&#xff1a;入门与实战 引言 Spring Boot 是 Spring 框架的一个子项目&#xff0c;旨在简化 Spring 应用的配置和开发。它通过自动配置和嵌入式服务器&#xff0c;极大地简化了 Java 企业级应用的开发。本文将详细介绍 Spring Boot 的核心概念&#xff…

【SPIE独立出版】第四届计算机、信息工程与电子材料国际学术会议 (CTIEEM 2024,2024年11月15-17日 )

第四届计算机、信息工程与电子材料国际学术会议 (CTIEEM 2024) The 4th International Conference on Computer Technology, Information Engineering and Electron Materials 会议官网&#xff1a;www.ctieem.org The 4th International Conference on Computer Technology,…

【bug】paddleocr draw_ocr_box_txt ValueError: incorrect coordinate type

【bug】paddleocr draw_ocr_box_txt ValueError: incorrect coordinate type 环境 python 3.10.15pillow 10.4.0 paddleocr 2.8.1错误详情 错误文本 Traceback (most recent call last):....draw_left.polygon(box, fillcolor)ValueError: inco…

浏览器内置文字转语音,播报功能Web Speech API - SpeechSynthesisUtterance

SpeechSynthesisUtterance: 让网页说话的艺术 在现代Web开发中&#xff0c;让网页具有语音功能可以极大提升用户体验&#xff0c;特别是对于视障用户或需要多任务处理的场景。SpeechSynthesisUtterance 是 Web Speech API 中的一个接口&#xff0c;它允许开发者创建一个语音合…

穷举vs暴搜vs深搜vs回溯vs剪枝(一)

文章目录 全排列子集找出所有子集的异或总和再求和全排列 II电话号码的字母组合 全排列 题目&#xff1a;全排列 思路 通过深度优先搜索的方式&#xff0c;不断枚举每个数在当前位置的可能性&#xff0c;然后回溯到上一个状态&#xff0c;直到枚举完所有可能性得到正确的结果 r…

SDK5(note上)

以下代码实现菜单窗口和快捷键的ctrlo打开的操作 #include <windows.h> #include<tchar.h> #include <stdio.h> #include <strsafe.h> #include <string> #define IDM_OPEN 102 /*鼠标消息 * 键盘消息 * Onkeydown * Onkeyup * //键盘扫描码 * …

力扣hot100--二叉树

目录 二叉树 1. 94. 二叉树的中序遍历 2. 98. 验证二叉搜索树 3. 101. 对称二叉树 4.102. 二叉树的层序遍历 5. 104. 二叉树的最大深度 6. 105. 从前序与中序遍历序列构造二叉树 7. 114. 二叉树展开为链表 8. 226. 翻转二叉树 9. 236. 二叉树的最近公共祖先 二叉树 …

操作符详解(C 语言)

目录 一、操作符的分类二、算数操作符1. 除法操作符2. 取余操作符 三、位移操作符1. 进制2. 原码、反码和补码3. 左移操作符&#xff08;<<&#xff09;和右移操作符&#xff08;>>&#xff09; 四、位操作符1. 按位与 &2. 按位或 |3. 按位异或 ^4. 按位取反 ~…

大衍数列——考研408考试科目之数据算法——未来之窗学习通

一、大衍数列 中国古代文献中&#xff0c;曾记载过“大衍数列”, 主要用于解释中国传统文化中的太极衍生原理。 它的前几项是&#xff1a;0、2、4、8、12、18、24、32、40、50 … 其规律是&#xff1a;对偶数项&#xff0c;是序号平方再除2&#xff0c;奇数项&#xff0c;是…

有源滤波器(三)

这个连接方法很可以&#xff0c;正好解决了最近没有转接器的问题&#xff1a;

javaweb-xml映射文件编写sql语句

可以使用注解的方式&#xff0c;也可以使用xml映射的方式&#xff0c;一般简单sql语句使用注解&#xff0c;复杂的使用xml映射。

【PhpSpreadsheet】ThinkPHP5+PhpSpreadsheet实现批量导出数据

目录 前言 一、安装 二、API使用 三、完整实例 四、效果图 前言 为什么使用PhpSpreadsheet&#xff1f; 由于PHPExcel不再维护&#xff0c;所以建议使用PhpSpreadsheet来导出exlcel&#xff0c;但是PhpSpreadsheet由于是个新的类库&#xff0c;所以只支持PHP7.1及以上的版…

【文心智能体 | AI大师工坊】如何使用智能体插件,完成一款购物类智能体的开发,来体验一下我的智能体『科技君Tom』

目录 1.1、智能体运行效果1.2、创作灵感来源智能体平台拥有个人化且人性化的大致框架&#xff0c;可以让小白也能搭建出一个智能体其次是拥有丰富的插件&#xff0c;可以更加快速的得到自己想要的效果~ 1.3、如何制作智能体常见问题与解决方案关于人设与回复逻辑插件使用模型的…

【黑马redis高级篇】持久化

//来源[01,05]分布式缓存 除了黑马&#xff0c;还参考了别的。 目录 1.单点redis问题及解决方案2.为什么需要持久化&#xff1f;3.Redis持久化有哪些方式呢&#xff1f;为什么我们需要重点学RDB和AOF&#xff1f;4.RDB4.1 定义4.2 触发方式4.2.1手动触发save4.2.2被动触发bgsa…