Qt QWidget 简约美观的加载动画 第四季

😊 第四季来啦 😊
效果如下:
在这里插入图片描述
只有三个文件,可以直接编译运行的

//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 JellyInBox;mainLayout->addWidget(anim1,0,0);auto* anim2 = new HorizontalDNA;mainLayout->addWidget(anim2,0,1);auto * anim3 = new  LoopedRingWithText;mainLayout->addWidget(anim3,1,0);auto* anim4 = new Radar;mainLayout->addWidget(anim4,1,1);w.setLayout(mainLayout);w.show();anim1->start();anim2->start();anim3->start();anim4->start();return a.exec();
}
//LoadingAnimWidget.h
#ifndef LOADINGANIMWIDGET_H
#define LOADINGANIMWIDGET_H
#include <QPropertyAnimation>
#include <QWidget>
class LoadingAnimBase:public QWidget
{Q_OBJECTQ_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 JellyInBox:public LoadingAnimBase{//一个会伸缩的果冻在一个小盒子里面,一开始拉伸,然后移动,然后收缩
public:explicit JellyInBox(QWidget* parent = nullptr);
protected:void paintEvent(QPaintEvent *event);
};
class HorizontalDNA:public LoadingAnimBase{//两根水平方向的小球链,螺旋滚动,像DNA双分子链
public:explicit HorizontalDNA(QWidget* parent = nullptr);
protected:void paintEvent(QPaintEvent*);
private:void getPosYAlphaScale(const int amplitude,const qreal & offset,qreal & y,qreal & alpha,qreal & scale);//根据原始偏移获取当前时间点下的y轴坐标,透明度,和缩放比例
};
class LoopedRingWithText:public LoadingAnimBase{//外面有三圈圆环转动,中间有一个高亮的灯光从左向右移动照亮字符串的一部分
public:explicit LoopedRingWithText(QWidget* parent = nullptr);
protected:void paintEvent(QPaintEvent*);
};
class Radar:public LoadingAnimBase{//像一个雷达一样扫描,等待耗时操作的结束
public:explicit Radar(QWidget* parent = nullptr);
protected:void paintEvent(QPaintEvent*);
};#endif // LOADINGANIMWIDGET_H
//LoadingAnimWidget.cpp
#include "LoadingAnimWidget.h"
#include <QDebug>
#include <QPaintEvent>
#include <QPainter>
#include <QtMath>
LoadingAnimBase::LoadingAnimBase(QWidget* parent):QWidget(parent){mAnim.setPropertyName("angle");mAnim.setTargetObject(this);mAnim.setDuration(2000);mAnim.setLoopCount(-1);//run forevermAnim.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();
}
JellyInBox::JellyInBox(QWidget* parent):LoadingAnimBase (parent){}
void JellyInBox::paintEvent(QPaintEvent *event){QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);painter.setBrush(Qt::NoBrush);int x = this->width();const int y = this->height();//先画一个盒子QPen pen("black");pen.setWidth(3);painter.setPen(pen);painter.drawRoundedRect(QRectF(1,0.4375*y,x-2,y/8),y/16.0,y/16.0);//画果冻pen.setCapStyle(Qt::RoundCap);painter.setBrush(Qt::NoBrush);const int gap = 4;//果冻和盒子之间的间距const int boxGap = 1;//盒子的外间距const qreal jh = y/8 - gap*2;//果冻高度pen.setWidthF(jh);painter.setPen(pen);painter.translate(boxGap + gap + jh/2,y/2);x -= (boxGap + gap) * 2 + jh;//可以移动的x范围是总宽度 - 两边的两个间距 - 笔头厚度const qreal maxw = 0.4*x;//最大的果冻宽度int jx = 0;qreal jw = 0;if(mAngle < 90){jw = maxw * mAngle / 90;}else if(mAngle < 270){jw = maxw;jx = (x - maxw) * (mAngle - 90) / 180;}else{jx = x - maxw + (mAngle - 270) / 90 * maxw;jw = x - jx;}painter.drawLine(jx,0,jx+jw,0);
}
HorizontalDNA::HorizontalDNA(QWidget* parent):LoadingAnimBase (parent){mAnim.setDuration(5000);
}
void HorizontalDNA::getPosYAlphaScale(const int amplitude,const qreal & offset,qreal & y,qreal & alpha,qreal & scale){static const qreal a = 2*3.1415926 / 360;//qreal x = a*mAngle + offset;//随着时间的流逝,x变大,y踩着着右边的值,看上去就是右边的小球带动左侧的小球移动//如果要实现左边的小球带动右侧的小球,要这样auto x = -a * mAngle + offset;y = qSin(x);auto tmp = qCos(x); //随着时间的流逝,x变小,当小球向上移动的时候,透明度变小tmp += 1;tmp /= 2;alpha = 1- tmp;scale = alpha / 2 + 0.5;//不要太小了,最小是0.5y *= amplitude;//amplitude就是振幅 sin(x)的振幅是1
}
void HorizontalDNA::paintEvent(QPaintEvent*){QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);painter.setPen(Qt::NoPen);const int x = width();const qreal radius = x / 20.0;//小球的半径const qreal y = height();const qreal unitx = x / 8.0;//小球的间距painter.translate(unitx,y/2);static const qreal gap = M_PI / 6;static const qreal offsetList[7] = {gap*0,gap*1,gap*2,gap*3,gap*4,gap*5,gap*6};QColor ballColor("black");for(int i = 0;i < 7;++i){qreal bally ,alpha,scale;getPosYAlphaScale(y/6,offsetList[i],bally,alpha,scale);ballColor.setAlphaF(alpha);painter.setBrush(QBrush(ballColor));painter.drawEllipse(QPointF(unitx*i,bally),radius*scale,radius*scale);}static const qreal offsetList2[7] = {gap*6,gap*7,gap*8,gap*9,gap*10,gap*11,0};for(int i = 0;i < 7;++i){qreal bally ,alpha,scale;getPosYAlphaScale(y/6,offsetList2[i],bally,alpha,scale);ballColor.setAlphaF(alpha);painter.setBrush(QBrush(ballColor));painter.drawEllipse(QPointF(unitx*i,bally),radius*scale,radius*scale);}
}
LoopedRingWithText:: LoopedRingWithText(QWidget* parent):LoadingAnimBase(parent){mAnim.setDuration(6000);
}
void  LoopedRingWithText::paintEvent(QPaintEvent*){QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);const int x = width();const int y = height();//step0:定义一些颜色变量,也可以改成成员变量static const QColor bright("turquoise");//最亮的圆环颜色static const QColor medium = QColor(bright.red(),bright.green(),bright.blue(),200);static const QColor dim = QColor(bright.red(),bright.green(),bright.blue(),160);//step1:画一个深色的背景painter.setPen(Qt::NoPen);painter.setBrush(QBrush(QColor("dimgray")));painter.drawRoundedRect(this->rect(),x/12,x/12);//step2:画最外面的两个圆环painter.translate(x/2,y/2);QPen pen(dim);pen.setWidth(4);pen.setCapStyle(Qt::RoundCap);painter.setPen(pen);const auto rect1 = QRectF(-0.45*x,-0.45*y,0.9*x,0.9*y);static const qreal start = 30;static const qreal span = 120;auto ang = mAngle;painter.rotate(ang);painter.drawArc(rect1,start * 16,span * 16);painter.drawArc(rect1,(start+180) *16,span * 16);painter.resetTransform();//step3:画中间的两个圆环pen.setColor(medium);painter.setPen(pen);painter.translate(x/2,y/2);const auto rect2 = QRectF(-0.375*x,-0.375*y,0.75*x,0.75*y);if(ang > 180) ang -= 180;//周期改成180,比外面的转的快一倍painter.rotate(-2*ang);painter.drawArc(rect2,start * 16,span * 16);painter.drawArc(rect2,(start + 180)*16,span*16);painter.resetTransform();//step4:画内部的4个圆环pen.setColor(bright);painter.setPen(pen);painter.translate(x/2,y/2);const auto rect3 = QRectF(-0.3*x,-0.3*y,0.6*x,0.6*y);ang = mAngle;static const qreal t3 = 120;//周期改成120,比中间的更快while(ang > t3) ang -= t3;painter.rotate( ang * 90 / t3);//四个圆环转过90度的时候也就是长短交替一次,要把这个转过的角度乘以调整系数:90/120qreal start0 = 15 + (90-15) * (ang / t3);//开始的时候上方圆环起点在15度,变化到90度时弧长为0qreal span0 = 180 - 2*start0;if(span0 > 0){//第一组painter.drawArc(rect3,start0*16 , span0*16);painter.drawArc(rect3,(start0+180)*16,span0*16);}start0 = -75 * (ang / t3);//开始的时候,右侧圆环起点是0,弧长为0,它的最大弧长时刻,起点在-75度span0 = -start0 * 2;if(span0 > 0){//第二组painter.drawArc(rect3,start0*16,span0*16);painter.drawArc(rect3,(start0+180)*16,span0*16);}painter.resetTransform();QFont font("Microsoft YaHei",12,4);painter.setFont(font);QFontMetrics fm(font);static const QString text("Loading...");qreal textw = fm.horizontalAdvance(text);qreal texth = fm.height();QPainterPath pp;pp.addText(QPointF( (x - textw)/2,0.5*y + texth/4),font,text);painter.setClipPath(pp);painter.setPen(Qt::NoPen);painter.setBrush(QBrush(dim));//step5: 先画一个淡色的文本painter.drawRect(rect());//step6: 最后一步啦,画一个圆灯光painter.translate(0,0.5*y);const qreal unit = x / 360.0;QRadialGradient grad(QPointF(mAngle*unit,0),texth);grad.setColorAt(0,bright);grad.setColorAt(1,dim);painter.setBrush(grad);painter.drawEllipse(QPointF(mAngle * unit,0),texth,texth);
}
Radar::Radar(QWidget* parent):LoadingAnimBase(parent){}
void Radar::paintEvent(QPaintEvent*){QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);//step1: 画一个淡色背景,很多简约的界面都需要透明背景,这一步可以删掉painter.setPen(Qt::NoPen);painter.setBrush(QBrush("deepskyblue"));const int x = width();const int y = height();painter.drawRoundedRect(rect(),x/12,x/12);//step2: 画一个雷达painter.translate(x/2,y/2);QConicalGradient gra(QPointF(0,0),45);static const QColor color0("white");static const QColor color1(color0.red(),color0.green(),color0.blue(),100);gra.setColorAt(0,color0);gra.setColorAt(0.2,color1);gra.setColorAt(1,"transparent");painter.setBrush(gra);painter.rotate(mAngle);const auto rect = QRectF(-x/4,-y/4,x/2,y/2);painter.drawPie(rect,45*16,90*16);}

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

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

相关文章

matlab 三质量-弹簧系统受激振力

1、内容简介 略 44-可以交流、咨询、答疑 建立系统运动方程&#xff0c;研究固有频率和对应主振型 2、内容说明 略 三质量&#xff0d;弹簧系统受激振力&#xff0c;并不考虑各自的阻尼。建立系统运动方程。 解&#xff1a;由于阻尼对固有频率没有影响&#xff0c;故本文不…

【蓝桥杯省赛真题25】python密室逃脱游戏 青少年组蓝桥杯比赛python编程省赛真题解析

目录 python密室逃脱游戏 一、题目要求 1、编程实现 2、输入输出

【深入理解设计模式】代理设计模式

代理设计模式&#xff1a; 代理设计模式是一种结构型设计模式&#xff0c;它允许你提供一个替代物或占位符来控制对其他对象的访问。在代理模式中&#xff0c;一个类代表另一个类的功能。这种类型的设计模式属于结构型模式&#xff0c;因为该模式涉及类和对象的组合。 概述 …

常见集合框架底层原理

常见集合框架底层原理 常见的集合有哪些 Java集合类主要由两个接口Collection和Map派生出来的&#xff0c;Collection有三个子接口: List、 Set、Queue List代表了有序可重复集合&#xff0c;可直接根据元素的索引来访问Set代表了无序集合&#xff0c;只能根据元素本身来访问…

代码随想录算法训练营第62天 | 739.每日温度 496.下一个更大元素I

每日温度 如果我们单纯的遍历数组&#xff0c;我们不知道当前元素是否比之前的元素大&#xff0c;所以需要维护一个容器来记录遍历过的元素。 什么时候用单调栈&#xff1f;通常是一维数组&#xff0c;要寻找任一个元素的右边或左边第一个比自己大或小的元素的位置。时间复杂度…

Linux-实用操作(黑马学习笔记)

各类小技巧&#xff08;快捷键&#xff09; ctrl c 强制停止 ● Linux某些程序的运行&#xff0c;如果想要强制停止它&#xff0c;可以使用快捷键ctrl c ● 命令输入错误&#xff0c;也可以通过快捷键ctrl c&#xff0c;退出当前输入&#xff0c;重新输入 ctrl d 退出或登…

客户端订阅服务端事件的机制

一、场景描述 产业大脑平台是一个典型的审核系统&#xff0c;用户发布到平台的信息需要经过审核员审核后生效。 用户发布信息->审核员审核信息->用户信息生效&#xff0c;这一流程可能发生在用户的同一次登录周期内。为了使客户端能实时响应信息的状态变化&#xff0c;…

使用Node.js和Vue.js构建全栈Web应用

随着互联网的迅速发展&#xff0c;Web应用程序的开发变得越来越复杂和多样化。为了满足用户不断变化的需求&#xff0c;全栈开发已成为一个备受关注的话题。在本篇博客中&#xff0c;我将介绍如何使用Node.js和Vue.js来构建全栈Web应用。 Node.js是一个基于Chrome V8引擎的Jav…

AI之T2I:Stable Diffusion 3的简介、安装和使用方法、案例应用之详细攻略

AI之T2I&#xff1a;Stable Diffusion 3的简介、安装和使用方法、案例应用之详细攻略 目录 Stable Diffusion 3的简介 1、效果测试 官方demo 网友提供 Stable Diffusion 3的安装和使用方法 1、安装 2、使用方法 Stable Diffusion 3的案例应用 1、基础案例 Stable Diff…

庖丁解牛-二叉树的遍历

庖丁解牛-二叉树的遍历 〇、前言 01 文章内容 一般提到二叉树的遍历&#xff0c;我们是在说 前序遍历、中序遍历、后序遍历和层序遍历 或者说三序遍历层序遍历&#xff0c;毕竟三序和层序的遍历逻辑相差比较大下面讨论三序遍历的递归方法、非递归方法和非递归迭代的统一方法然…

数据结构2月25日

第一道&#xff1a; 第二道&#xff1a; 1、插入到prev和next中间 1.new(struct list_head*)malloc(sizeof(struct list_head*)); if(newNULL) { printf("失败\n"); return; } new->nextprev->next; prev->nextnew; return; 2、删除prve和next…

Mybatis-Plus学习

文章目录 一、简介1. 概述2. 特点3. 框架架构 二、入门案例1. 数据库环境准备2. SpringBoot工程准备3. 配置application.yml4. 项目开发5. MybatisPlus测试 三、BaseMapper1. 源码2. 方法测试 四、IService1. 简介2. 使用IService3. 测试IService 五、MybatisPlus为我们提供的一…

大文件传输之udp如何传输大量数据

在数字化时代&#xff0c;对大文件传输的需求正以前所未有的速度增长。无论是个人用户还是企业&#xff0c;都急切寻求一种能够快速且稳定地处理大量数据的传输方法。UDP&#xff08;用户数据报协议&#xff09;以其无连接的特性和高效的数据传输能力&#xff0c;成为了大文件传…

啤酒:探索精酿啤酒与家常菜的温馨滋味

在繁忙的生活中&#xff0c;我们总是在寻找一种简单而温馨的美食享受。家常菜&#xff0c;作为最具代表性的传统美食&#xff0c;以其丰富的口味和深厚的情感价值而受到广泛欢迎。而当Fendi Club啤酒遇上家常菜&#xff0c;它们将共同演绎出一曲充满温情的味觉交响曲。 Fendi C…

抖音视频批量下载工具|抖音数据抓取工具

想要随时随地观看抖音平台上的精彩视频内容吗&#xff1f;不必担心&#xff01;这款基于C#开发的抖音视频下载工具将成为您的得力助手&#xff0c;让您轻松畅享最新、最热的视频内容。 【多功能实用】 无论是批量视频提取还是固定视频下载&#xff0c;这款工具都能满足您的需求…

第十三章 Linux——备份与恢复

第十三章 Linux——备份与恢复 基本介绍安装dump和restore使用dump完成备份dump语法说明dump应用案例1dump应用案例2dump-w查看备份时间文件备份文件或者目录备注 使用restore基本语法基本介绍restore基本语法应用案例1应用案例2应用案例3应用案例4 基本介绍 实体机无法做快照…

跨境支付介绍

1、跨境电商定义和分类&#xff1b; 2、国际贸易清结算&#xff1b; 3、跨境支付&#xff1b; 1、跨境电商定义和分类 跨境电商业务简单说就是指不同国家地域的主体通过电子商务进行交易的一种业务模式。同传统的电商不同&#xff0c;交易双方属于不同的国家。因此&#xff0…

成都直播基地作为产业重要载体,引领直播行业健康、多元发展

近年来&#xff0c;我国网络直播行业呈现出井喷式的发展态势。众多直播平台如雨后春笋般涌现&#xff0c;直播内容丰富多样&#xff0c;涵盖游戏、电竞、美食、旅游、教育等多个领域。同时&#xff0c;成都直播产业园规模持续扩大&#xff0c;产业不断完善&#xff0c;整体呈现…

免费享受企业级安全:雷池社区版WAF,高效专业的Web安全的方案

网站安全成为了每个企业及个人不可忽视的重要议题。 随着网络攻击手段日益狡猾和复杂&#xff0c;选择一个强大的安全防护平台变得尤为关键。 推荐的雷池社区版——一个为网站提供全面安全防护解决方案的平台&#xff0c;它不仅具备高效的安全防护能力&#xff0c;还让网站安…

【JavaScript 漫游】【021】EventTarget 接口

事件的本质是程序各个组成部分之间的一种通信方式&#xff0c;也是异步编程的一种实现。DOM 支持大量的事件。 EventTarget 接口概述 DOM 的事件操作&#xff08;监听和触发&#xff09;&#xff0c;都定义在 EventTarget 接口。所有节点对象都部署了这个接口&#xff0c;其他…