Qt QWiget 实现简约美观的加载动画 第三季

news2024/12/26 9:21:48

😃 第三季来啦 😃 这是最终效果:
在这里插入图片描述
只有三个文件,可以直接编译运行

//main.cpp
#include "LoadingAnimWidget.h"
#include <QApplication>
#include <QVBoxLayout>
#include <QGridLayout>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QWidget w;
    w.setWindowTitle("加载动画 第三季");
    QGridLayout * mainLayout = new QGridLayout;

    auto* anim1= new RippleWave;
    mainLayout->addWidget(anim1,0,0);

    auto* anim2 = new SlinkyCircle;
    mainLayout->addWidget(anim2,0,1);

    auto * anim3 = new ZoomingBalls;
    mainLayout->addWidget(anim3,1,0);

    auto* anim4 = new SpotFoldCircle;
    mainLayout->addWidget(anim4,1,1);

    w.setLayout(mainLayout);
    w.show();
    anim1->start();
    anim2->start();
    anim3->start();
    anim4->start();
    return a.exec();
}

//LoadingAnimWidget.cpp
#include "LoadingAnimWidget.h"
#include <QDebug>
#include <QPaintEvent>
#include <QPainter>
LoadingAnimBase::LoadingAnimBase(QWidget* parent):QWidget(parent){
    mAnim.setPropertyName("angle");
    mAnim.setTargetObject(this);
    mAnim.setDuration(2000);
    mAnim.setLoopCount(-1);//run forever
    mAnim.setEasingCurve(QEasingCurve::Linear);
    setFixedSize(200,200);
    mAngle = 0;
}
LoadingAnimBase::~LoadingAnimBase(){}
void LoadingAnimBase::exec(){
    if(mAnim.state() == QAbstractAnimation::Stopped){
        start();
    }
    else{
        stop();
    }
}
void LoadingAnimBase::start(){
    mAnim.setStartValue(0);
    mAnim.setEndValue(360);
    mAnim.start();
}
void LoadingAnimBase::stop(){
    mAnim.stop();
}
qreal LoadingAnimBase::angle()const{ return mAngle;}
void LoadingAnimBase::setAngle(qreal an){
    mAngle = an;
    update();
}

SlinkyCircle::SlinkyCircle(QWidget* parent):LoadingAnimBase (parent){
    mAnim.setEasingCurve(QEasingCurve::InOutCubic);
}
void SlinkyCircle::paintEvent(QPaintEvent *event){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::NoPen);
    //画圆弧
    painter.setBrush(Qt::NoBrush);
    const int x = this->width();
    const int y = this->height();
    QPen pen("black");
    pen.setCapStyle(Qt::RoundCap);
    pen.setWidth(x/20);
    painter.setPen(pen);

    painter.translate(x/2,y/2);

    static const qreal spanAngle = 90;//mAngle<=45,要把弧线拉伸出来
    static const qreal shrinkAngle = 360 - spanAngle;//mAngle==315时,要把弧线收缩起来

    auto arcRect = this->rect().adjusted(x/5,y/5,-x/5,-y/5);
    arcRect.translate(-x/2,-y/2);

    static const int direction = -1;//顺时针

    if(mAngle < spanAngle){
        painter.drawArc(arcRect,90 * 16,mAngle * 16 * direction);
    }
    else{//弧长是固定的
        //40 - 320 --> 320 , 280 --> 320
        if(mAngle > shrinkAngle){
            painter.drawArc(arcRect,90 * 16,-(360-mAngle)*16 * direction);
        }
        else{
            //我转动的角度是当前角度 - 拉伸门槛,因为有收尾的不动的时间段,占据了一段角度,所以要把转动的角度拉伸一些,
            //这个比例就是 (360-spanAngle) / (shrinkAngle - spanAngle)
            const auto delta = (mAngle - spanAngle) * (360-spanAngle) / (shrinkAngle - spanAngle);
            painter.rotate(-delta * direction);
            painter.drawArc(arcRect,90 * 16,spanAngle * 16 * direction);
        }
    }

}
ZoomingBalls::ZoomingBalls(QWidget* parent):LoadingAnimBase (parent){}

void ZoomingBalls::paintEvent(QPaintEvent *event){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::NoPen);

    //这里可以设置小球的颜色,也可以改成类的成员
    static const QStringList colorList{"black","black","black","black","black"};

    const int x = width();
    const int y = height();
    const qreal r = x/24;    //小球的半径
    const qreal rmax = x/10;  //小球最大半径
    const qreal alphaSpace = 0.8; //小球颜色变化范围
    static const int startAngle[5] = {0,45,90,135,180};//五个小球开始变化时间点
    painter.translate(x/6,y/2);

    for(int i = 0;i < colorList.size();++i){
        const auto start = startAngle[i];
        qreal delta = mAngle - start;

        QColor background = colorList[i];
        if(delta > 0 && delta < 180){
            if(delta > 90) delta = 180 - delta;
            qreal ratio = delta/ 90.0;
            qreal alpha = 1- ratio *alphaSpace;
            qreal radius = r + ratio * (rmax - r);
            background.setAlphaF(alpha);
            painter.setBrush(QBrush(background));
            painter.drawEllipse(QPointF(0,0),radius,radius);
        }
        else{//不变
            painter.setBrush(QBrush(background));
            painter.drawEllipse(QPointF(0,0),r,r);
        }
        painter.translate(x/6.0,0);
    }
}
SpotFoldCircle::SpotFoldCircle(QWidget* parent):LoadingAnimBase (parent){}

void SpotFoldCircle::paintEvent(QPaintEvent *event){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::NoPen);
    painter.setBrush(QBrush(QColor("black")));

    static const int startAngle[5] = {0,15,28,40,50}; //小球开始转动的开始时间点
    static const int restAngle = 360 - startAngle[4]; //小球休息的时间点
    static const qreal angleStretch = 360.0 / (360 - startAngle[4]); //角度拉伸比例

    const int x = this->width();
    const int y = this->height();
    painter.translate(x/2,y/2);

    const int radius = x / 16;//小球的半径
    static const qreal ratioList[5] = {1,0.8,0.64,0.512,0.41}; //小球半径比例列表 ,很明显,小球越来越小

    for(int i = 0;i < 5;++i){
        const int start = startAngle[i];
        const qreal r = radius * ratioList[i];
        qreal delta = mAngle - start;
        if(delta > 0 && delta < restAngle){ //要转动起来
            painter.rotate(delta * angleStretch);
            painter.drawEllipse(QPointF(0,-y/2 + radius*2),r,r);
            painter.rotate(-delta * angleStretch);
        }
        else{ //停在原地
            painter.drawEllipse(QPointF(0,-y/2 + radius*2),r,r);
        }
    }
}
RippleWave::RippleWave(QWidget* parent):LoadingAnimBase (parent){}

void RippleWave::paintEvent(QPaintEvent *event){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(Qt::NoBrush);
    QPen pen("black");
    pen.setWidth(3);
    //每层波浪的生命周期是6个单位,一共有八层,每层开始时间是前一层波浪的一个单位之后,时间共分为14个单位
    static const int arr[8] = {10,15,22,31,42,55,70,87};//波浪的半径
    static const qreal unit = 360.0 / 14;
    static const qreal startArr[8] = {0,unit,unit*2 , unit*3 ,unit*4,unit*5,unit*6,unit*7};
    static const qreal lifeSpan = unit*6;
    const int x = this->width();
    const int y = this->height();
    painter.translate(x/2,y/2);

    for(int i = 0;i < sizeof(arr) / sizeof(int);++i){
        const auto start = startArr[i];
        const auto delta = mAngle - start;
        qreal alpha = 1;
        if(delta > 0 && delta < lifeSpan){
            if(delta < unit*2) alpha = delta / (unit*2);
            if(delta > unit*4) alpha = (lifeSpan - delta) / (unit*2);
            QColor c("black");
            c.setAlphaF(alpha);
            pen.setColor(c);
            painter.setPen(pen);
            painter.drawEllipse(QPointF(0,0),arr[i],arr[i]);
        }
        else{
            //什么都不用做
        }
    }
}

//LoadingAnimWidget.h
#ifndef LOADINGANIMWIDGET_H
#define LOADINGANIMWIDGET_H
#include <QPropertyAnimation>
#include <QWidget>
class LoadingAnimBase:public QWidget
{
    Q_OBJECT
    Q_PROPERTY(qreal angle READ angle WRITE setAngle)
public:
    LoadingAnimBase(QWidget* parent=nullptr);
    virtual ~LoadingAnimBase();

    qreal angle()const;
    void setAngle(qreal an);
public slots:
    virtual void exec();
    virtual void start();
    virtual void stop();
protected:
    QPropertyAnimation mAnim;
    qreal mAngle;
};
class SlinkyCircle:public LoadingAnimBase{
    //可以伸缩的管子,绕着中心转动,就像弹簧圈,英语叫做slinky,查了好久才查到这个单词,有点强迫症😂
    Q_OBJECT
public:
    explicit SlinkyCircle(QWidget* parent = nullptr);
protected:
    void paintEvent(QPaintEvent *event);
};

class ZoomingBalls:public LoadingAnimBase{//五个小球,每个依次变大
    Q_OBJECT
public:
    explicit ZoomingBalls(QWidget* parent = nullptr);
protected:
    void paintEvent(QPaintEvent *event);
};

class SpotFoldCircle:public LoadingAnimBase{//五个小球绕中心旋转,可以折叠在一起
    Q_OBJECT
public:
    explicit SpotFoldCircle(QWidget* parent = nullptr);
protected:
    void paintEvent(QPaintEvent *event);
};

class RippleWave:public LoadingAnimBase{//8层波纹,从中间逐渐向外变亮,然后变暗
    Q_OBJECT
public:
    explicit RippleWave(QWidget* parent = nullptr);
protected:
    void paintEvent(QPaintEvent *event);
};

#endif // LOADINGANIMWIDGET_H

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

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

相关文章

架构设计:流式处理与实时计算

引言 随着大数据技术的不断发展&#xff0c;流式处理和实时计算在各行各业中变得越来越重要。那么什么是流式处理呢&#xff1f;我们又该怎么使用它&#xff1f;流式处理允许我们对数据流进行实时分析和处理&#xff0c;而实时计算则使我们能够以低延迟和高吞吐量处理数据。本…

axure9.0 工具使用思考

原型设计软件【AxureRP】快速原型设计工具原型设计软件【AxureRP】快速原型设计工具原型设计软件【AxureRP】快速原型设计工具原型设计软件【AxureRP】快速原型设计工具原型设计软件【AxureRP】快速原型设计工具原型设计软件【AxureRP】快速原型设计工具原型设计软件【AxureRP】…

linux中查找进程cpu使用率高的原因

查询哪些进程/线程cpu使用率高 使用 top 命令&#xff1a; 在终端中运行 top 命令&#xff0c;它会实时显示系统中正在运行的进程和线程&#xff0c;并按照 CPU 使用率进行排序。你可以按 Shift P 键按照 CPU 使用率对进程进行排序&#xff0c;或者按 Shift T 键按照线程进…

nginx基础模块配置详解

目录 一、Nginx相关配置 1、nginx配置文件 2、nginx模块 二、nginx全局配置 1、关闭版本或修改版本 1.1 关闭版本 1.2 修改版本 2、修改nginx启动的子进程数 3、cpu与worker进程绑定 4、PID路径 5、nginx进程的优先级 6、调试worker进程打开文件的个数 7、nginx服…

idea 设置启动类置底/设置folders置顶

在新建项目的时候启动类外和swagger交叉展示在包之间&#xff0c;缺少美观&#xff0c;这在一个有洁癖的程序员眼里是非常不能接受的。在网上大量检索相关的设置&#xff0c;一无所获。但是苍天犹怜&#xff0c;经过我一上午的探索&#xff0c;终于在一个犄角旮旯里面找到了这个…

【可实战】被测系统业务架构、系统架构、技术架构、数据流、业务逻辑分析

一、为什么要学习 更深的理解业务逻辑&#xff08;公司是做什么的&#xff1f;它最重要的商务决策是什么&#xff1f;它里面的数据流是怎么做的&#xff1f;有哪些业务场景&#xff1f;考验你对这家公司、对所负责业务的熟悉程度。公司背后服务器用什么软件搭建的&#xff1f;…

系统找不到xinput1_3.dll怎么办?试试这五种解决方法轻松搞定

在计算机系统运行过程中&#xff0c;当我们遭遇“找不到xinput1_3.dll”这一错误提示时&#xff0c;实际上正面临一个软件兼容性、系统组件缺失以及游戏或应用程序无法正常启动的关键问题。深入探究这一现象&#xff0c;我们会发现它可能引发一系列连带问题&#xff0c;例如某些…

蓝桥杯Learning

Part 1 递归和递推 1. 简单斐波那契数列 # 这里使用了数组进行保存 n int(input())st [0]*(47) # 注意这个地方&#xff0c;需要将数组空间设置的大一些&#xff0c;否则会数组越界 st[1] 0 st[2] 1def dfs(u):if u 1:print(st[1],end" ")if u 2:print(str(st[…

黑马程序员——接口测试——day03

目录&#xff1a; Potman断言 Postman断言简介Postman常用断言 断言响应状态码断言包含某字符串断言JSON数据Postman断言工作原理Postman关联 简介实现步骤核心代码创建环境案例1案例2Postman参数化 简介数据文件简介编写数据文件 CSV文件JSON文件导入数据文件到postman读取数…

数据安全治理实践路线(下)

数据安全运营阶段通过不断适配业务环境和风险管理需求&#xff0c;持续优化安全策略措施&#xff0c;强化整个数据安全治理体系的有效运转。 数据安全运营 1. 风险防范 数据安全治理的目标之一是降低数据安全风险&#xff0c;因此建立有效的风险防范手段&#xff0c;对于预防…

3、函数定义,函数调用,this指向总结,闭包

一、函数的定义方式 1、函数声明 function demo1() {var num 12var result Math.pow(num,2)//指数函数return result }2、函数表达式 var demo2 function (x,y) { //内置对象arguments前面的两个参数 是 x,yvar sum arguments[0] arguments[1]console.log(sum) }3、构…

web组态插件

插件演示地址&#xff1a;http://www.byzt.net 关于组态软件&#xff0c;首先要从组态的概念开始说起。 什么是组态 组态&#xff08;Configure&#xff09;的概念来自于20世纪70年代中期出现的第一代集散控制系统&#xff08;Distributed Control System&#xff09;&#xf…

docker build基本命令

背景 我们经常会构建属于我们应用自己的镜像&#xff0c;这种情况下编写dockerfile文件不可避免&#xff0c;本文就来看一下常用的dockerfile的指令 常用的dockerfile的指令 首先我们看一下docker build的执行过程 ENV指令&#xff1a; env指令用于设置shell的环境变量&am…

渗透测试—信息收集

渗透测试—信息收集 1. 收集域名信息1.1. 域名注册信息1.2. SEO信息收集1.3. 子域名收集1.3.1. 在线子域名收集1.3.2. 子域名收集工具 1.4. 域名备案信息1.5. ICP备案号查询1.6. SSL证书查询 2. 收集真实IP2.1. 超级ping2.2. Ping2.3. CDN绕过 3. 收集旁站或C段IP3.1. 旁站或C段…

一款非常专业的图形设计工具CorelDRAW2024中文破解版

CorelDRAW2024&#xff08;简称CDR2024&#xff09;是一款非常专业的图形设计工具&#xff0c;该产品推出了全新的2023版本&#xff0c;在功能和体验上更进一步&#xff0c;最新的填充和透明设备功能可以完全控制任何类型的纹理&#xff0c;适用于网络摄影、印刷项目、艺术、排…

【析】装卸一体化车辆路径问题的自适应并行遗传算法

0 引言 国内外有关 &#xff36;&#xff32;&#xff30;&#xff33;&#xff30;&#xff24;的文献较多&#xff0c;求解目标多以最小化车辆行驶距离为主&#xff0c;但现实中可能存在由租赁费用产生的单次派出成本&#xff0c;需要综合考 虑单次派车成本和配送路径成本。…

JetBrains系列工具,配置PlantUML绘图

PlantUML是一个很强大的绘图工具&#xff0c;各种图都可以绘制&#xff0c;具体的可以去官网看看&#xff0c;或者百度。 PlantUML简述 https://plantuml.com/zh/ PlantUML语言参考指引 https://plantuml.com/zh/guide PlantUML语言是依赖Graphviz进行解析的。Graphviz是开源…

Superhuman 邮箱的替代方案是什么?

Superhuman是一个极好的人工智能工具在电子邮件助理领域。根据SimilarWeb的最新统计&#xff0c;它在全球网站排名中排名第21980位&#xff0c;月访问量为1751798。然而市场上还有许多其他优秀的选择。为了帮助您找到最适合您需求的解决方案&#xff0c;我们为您精心挑选了10种…

快让Live2D小可爱住进你的网站吧

文章目录 一、效果请欣赏二、教程1.下载项目工程2.本地自行修复测试3. 测试 一、效果请欣赏 二、教程 1.下载项目工程 github地址 可以根据工程的readme来使用demo测试&#xff0c;demo中需要修改 autoload.js api的cdnPath或者apiPath&#xff0c;否则加载不出来人物图片 api…

10个Premiere创意设计项目列表文字清单视频模板素材

10个创意设计项目列表文字清单pr模板视频制作素材&#xff0c;高清分辨率&#xff1a;19201080&#xff0c;Premiere Pro 2019项目&#xff0c;无需插件&#xff0c;包括视频教程&#xff0c;预览图像不包括音频不包括。 更多PR素材下载&#xff1a;https://prmuban.com/37908.…