Qt 简约美观的加载动画 小沙漏风格 第六季

这次和大家分享一个沙漏风格的加载动画
效果如下:
在这里插入图片描述

这是本系列的第六季了, 本次内容的关键在于cubicTo函数的使用, 在这里分享一个非常好用的网站https://www.desmos.com/calculator/cahqdxeshd
在这上面可以手动拖动贝塞尔曲线的控制点, 并且显示了起终点和两个控制点的精确坐标, 这样来使用qt的cubicTo函数就非常方便了.

一共三个文件,可以直接编译运行

//main.cpp
#include "LoadingAnimWidget.h"
#include <QApplication>
#include <QGridLayout>
int main(int argc, char *argv[])
{QApplication a(argc, argv);QWidget w;w.setWindowTitle("加载动画 第6季");QGridLayout * mainLayout = new QGridLayout;auto* anim1= new FillGlassBead;mainLayout->addWidget(anim1,0,0);auto* anim2 = new FillGlassBead;anim2->setWaveType(FillGlassBead::WaveType::SwayingWater);mainLayout->addWidget(anim2,0,1);auto* anim3 = new Hourglass;mainLayout->addWidget(anim3,1,0);auto* anim4 = new Hourglass;anim4->setColumnVisibility(true);anim4->setSandColor("seagreen");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 FillGlassBead:public LoadingAnimBase{
public:FillGlassBead(QWidget* parent = nullptr);//一颗玻璃珠,内部逐渐充满液体enum class WaveType{PeacefulWater /*平静的水面*/ , SwayingWater /*左右晃动的水面*/};void setWaveType(WaveType t);
protected:void paintEvent(QPaintEvent*);
private:WaveType mWaveType;
};
class Hourglass:public LoadingAnimBase{
public:Hourglass(QWidget* parent = nullptr);//沙漏void setSandColor(const QColor& color);//设置沙子颜色void setColumnVisibility(bool vis);//设置柱子可见性
protected:void paintEvent(QPaintEvent*);
private:QColor mSandColor;bool mColumnVisible;
};
#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();
}
FillGlassBead::FillGlassBead(QWidget* parent):LoadingAnimBase (parent){mAnim.setDuration(3600);mWaveType = WaveType::PeacefulWater;
}
void FillGlassBead::setWaveType(WaveType t){if(mWaveType != t){mWaveType = t;update();}
}
void FillGlassBead::paintEvent(QPaintEvent* e){QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);const int x = width();const int y = height();static const QColor color("lightseagreen");if(mAngle < 90){//只要画一个坠落的小球painter.translate(x/2,0);painter.setPen(Qt::NoPen);painter.setBrush(QBrush(color));qreal posY = y/4.0 * mAngle / 90;//坠落的小球最低点是高度的四分之一painter.drawEllipse(QPointF(0,posY),5,5);}else{painter.translate(x/2,0.625*y);QPen pen(color);pen.setWidth(4);painter.setPen(pen);painter.setBrush(Qt::NoBrush);const qreal r = 0.375*y;if(mAngle < 225){//画一个包裹玻璃珠的圆环//最高点起点角度是90,弧长是0,最低点起点角度是-90,弧长是360qreal proportion = (mAngle - 90) / 135.0;painter.drawArc(QRectF(-r,-r,2*r,2*r), 16*(90-180*proportion),16*360*proportion);}else{//画一个退去的包裹圆环//最开始起点角度是-90,最后起点角度是90qreal proportion = (mAngle - 225) / 135.0;painter.drawArc(QRectF(-r,-r,2*r,2*r),16*(-90+180*proportion),16*(360 - proportion*360));//再画一个上涨的水波QPainterPath pp;const qreal startx = -x/2;const qreal starty = 0.375*y - 0.75*y*proportion;if(mWaveType == WaveType::PeacefulWater){pp.addRect(QRectF(startx,starty,x,y));}else{QPointF start(startx,starty);QPointF end(start.x() + x,start.y());const qreal h = qSin(4*M_PI * proportion) *x * 0.3;QPointF c1( start.x() + 0.25*x, start.y() + h);QPointF c2( start.x() + 0.75*x, start.y() - h);pp.moveTo(start);pp.cubicTo(c1,c2,end);pp.lineTo(end.x(),999);//999没有具体含义,大一点就行了pp.lineTo(startx,999);pp.closeSubpath();}painter.setClipPath(pp);painter.setPen(Qt::NoPen);painter.setBrush(QBrush(color));const qreal r2 = r - 4;painter.drawEllipse(QRectF(-r2,-r2,2*r2,2*r2));}}
}
Hourglass::Hourglass(QWidget* parent):LoadingAnimBase (parent),mSandColor("lime"),mColumnVisible(false){ }
void Hourglass::setSandColor(const QColor& color){if(mSandColor != color){mSandColor = color;update();}
}
void Hourglass::setColumnVisibility(bool vis){if(vis != mColumnVisible){mColumnVisible = vis;update();}
}
void Hourglass::paintEvent(QPaintEvent*){QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);const qreal x = width();const qreal y = height();//step1: 先画上下两个瓶盖qreal ang = (mAngle - 320)/40;//到320度的时候要旋转瓶子if(ang > 1) ang = 1;if(ang < 0) ang = 0;ang *= 180;QPen pen("lightslategray");//岩灰色的瓶身,就像我冰冷的内心pen.setWidth(16);pen.setCapStyle(Qt::RoundCap);painter.setBrush(Qt::NoBrush);painter.setPen(pen);painter.translate(x/2,y/2);painter.rotate(ang);painter.drawLine(-x/4,-0.375*y,x/4,-0.375*y);//上方瓶盖painter.drawLine(-x/4,0.375*y,x/4,0.375*y);//  下方瓶盖//step2: 画一个瓶身QPainterPath pp;const int gap1 = 8;//瓶身距离四分之一水平位置的间距,这个值越大,沙漏越瘦QPointF start(-x/4 + gap1 , -0.375*y);QPointF end(-x/32 , 0);QPointF c1(start.x(),end.y());QPointF c2(end.x(),end.y() + 0.4 * (start.y() - end.y()));pp.moveTo(start);pp.cubicTo(c1,c2,end);const qreal penWidth = 6;pen.setWidthF(penWidth);painter.setPen(pen);painter.drawPath(pp);//瓶身轮廓左上部分painter.rotate(180);painter.drawPath(pp);//右下painter.rotate(-180);painter.scale(1,-1);painter.drawPath(pp);//右上painter.rotate(180);painter.drawPath(pp);//左下//step3: 画两根小柱子(可选)if(mColumnVisible){pen.setWidthF(4);painter.setPen(pen);painter.drawLine(-x/4,start.y(),-x/4,-start.y());painter.drawLine(x/4,start.y(),x/4,-start.y());}painter.resetTransform();painter.translate(x/2,y/2);painter.setPen(Qt::NoPen);painter.setBrush(QBrush(mSandColor));if(mAngle < 320){ //step4: 画动态的沙子//画上面的沙子QPainterPath sand;start.setX(start.x() + penWidth/2);//沙子区域要瘦一点,免得盖住了瓶身end.setX(end.x() + penWidth/2);    //沙子区域要瘦一点,免得盖住了瓶身c1.setX(c1.x() + penWidth/2);      //沙子区域要瘦一点,免得盖住了瓶身c2.setX(c2.x() + penWidth/2);      //沙子区域要瘦一点,免得盖住了瓶身sand.moveTo(start);sand.cubicTo(c1,c2,end);sand.lineTo(0,(0.33-0.2*mAngle/320)*y);sand.lineTo(QPointF(end.x()*-1,end.y()));sand.cubicTo(QPointF(-c2.x(),c2.y()),QPointF(-c1.x(),c1.y()),QPointF(-start.x(),start.y()));sand.lineTo(start);painter.setClipPath(sand);painter.drawRect(QRectF(-x/2,-y/4+mAngle/320 * y *0.38,x,x));//画下面的沙子, 一个等腰三角形QPointF a(start.x() * mAngle/320,0.33*y);QPointF top(0,(0.33 - mAngle/320 * 0.2) * y);QPointF b(-a.x(),a.y());sand.moveTo(a);sand.lineTo(top);sand.lineTo(b);sand.closeSubpath();painter.setClipPath(sand);painter.drawRect(-x/2,top.y(),x,x);//这个高度不能太随意,否则会把上面的沙子也画出来}else{//旋转沙子QPainterPath pp;pp.moveTo(QPointF(start.x() + penWidth/2,0.33*y));pp.lineTo(0,0.13*y);pp.lineTo(QPointF(-start.x()-penWidth/2,0.33*y));pp.closeSubpath();QTransform bottoleTrans;bottoleTrans.rotate(ang);painter.setClipPath(bottoleTrans.map(pp));painter.drawRect(QRectF(-x/2,-x/2,x,x));}
}

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

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

相关文章

Linux中如何在创建子线程的时候设置为分离属性

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/types.h> #include<unistd.h> #include <pthread.h> void *mythread(void *arg) {printf("id[%ld]\n",pthread_self()); } int main() { //定义pthread_…

ulimit命令

ulimit命令 ulimit 命令用于查看和设置 shell 运行时的资源限制。它可以控制各种资源&#xff0c;如文件打开数量、堆栈大小、CPU 时间等。ulimit 命令通常用于限制 shell 启动的进程的资源使用量&#xff0c;以防止系统资源被耗尽。ulimit命令的主要作用是提高系统的性能和稳…

智能水表预付费管理系统

智能水表预付费管理系统是当前智能水表技术的重要应用之一&#xff0c;结合了智能化管理和预付费功能&#xff0c;为水务公司和用户提供了便捷、高效的用水管理解决方案。该系统利用先进的科技手段&#xff0c;实现了水表抄表、计费和管理的自动化&#xff0c;为用户带来更便捷…

【粉丝福利第一期】小 明

Q1 - 能否自我介绍下&#xff1f; 嗨&#xff0c;大家好&#xff0c;我是 小 明 &#xff08;小明java问道之路&#xff09;&#xff0c;互联网大厂后端研发专家&#xff0c;2022博客之星TOP3/博客专家/CSDN后端内容合伙人、InfoQ(极客时间)签约作者、阿里云签约博主、全网5万…

PBM学习——从基础到精通!!!

本专栏着重讲解PBM学习所得,学习笔记、心得,并附有视频素材资料,视频详细目录如下: PBM相关参数解释1 PBM相关参数解释2 PBM相关案例实践1 PBM相关案例实践2 PBM相关案例实践2 PBM相关案例实践3 PBM多相流中次相界面设置1 PBM多相流中次相界面设置2 欧拉多相流曳力1 欧拉多…

make/makefile

首先什么是make和makefile呢&#xff1f;先简单说&#xff0c;make是一条命令&#xff0c;makefile是一个文件&#xff0c;这个文件中存的是依赖关系和依赖方法&#xff0c;那么为什么会有这两个东西呢&#xff1f; 首先我们知道在VS2019中&#xff0c;我们可以直接创建一个工程…

Linux系统中make/Makefile的介绍

文章目录 前言一、make命令二、makefile功能介绍1.makefile文件的编写格式2.hello.c文件内容3.makefile文件4.安装make命令 总结 前言 在linux系统中&#xff0c;我们对项目文件进行处理的时候会不方便&#xff0c;因此我们需要对文件的编译进行自动化处理。 下面就是在Linux系…

1、docker 基础命令

1、docker 运行镜像 docker run image tag 2、创建dockerfile&#xff08;构建容器的相关命令&#xff09; vim DockerFile 3、docker 构建容器镜像 docker build -t <image_name> . 4、docker 分层 5、查看镜像 docker images 6、docker 执行 docker run --name &…

web组态(BY组态)接入流程

技术文档 官网网站&#xff1a;www.hcy-soft.com 体验地址&#xff1a; www.byzt.net:60/sm 一、数据流向图及嵌入原理 数据流向 嵌入原理 二、编辑器调用业务流程图 三、集成前需要了解的 1、后台Websocket端往前台监控画面端传输数据规则 后台websocket向客户端监控画面…

模型优化_XGBOOST学习曲线及改进,泛化误差

代码 from xgboost import XGBRegressor as XGBR from sklearn.ensemble import RandomForestRegressor as RFR from sklearn.linear_model import LinearRegression as LR from sklearn.datasets import load_boston from sklearn.model_selection import train_test_split,c…

Linux: GDB 调试工具

概念&#xff1a; Linux GDB&#xff08;GNU Debugger&#xff09;是一个功能强大的调试工具&#xff0c;用于调试C、C等编程语言的程序。它可以帮助开发人员定位和修复程序中的错误。 GDB 的使用 &#xff1a; 激活和进入工作模式&#xff1a; gdb 需要调试的文件 进入 …

【Java设计模式】三、

文章目录 0、案例&#xff1a;咖啡屋1、简单工厂模式 静态工厂&#xff08;不属于23种之列&#xff09;2、工厂方法模式3、抽象工厂模式4、建造者模式5、原型设计模式 0、案例&#xff1a;咖啡屋 模拟咖啡店点餐。咖啡有多种&#xff0c;抽象类&#xff0c;子类为各种咖啡。咖…

2.29作业

T课上实现通信代码总结&#xff1a; 程序代码&#xff1a; TCPSER.c #include<myhead.h> #define SER_IP "192.168.244.140" //服务器IP #define SER_PORT 9999 //服务器端口号 int main(int argc, const char *argv[]) {//1.创建用于监…

为什么猫咪挑食不吃猫粮?适口性好、普口性价的主食冻干推荐

现代养猫人士往往把自家的小猫看作是生活中的小宝贝&#xff0c;十分宠爱。最令人头疼的就是猫咪挑食不吃猫粮&#xff0c;为什么猫咪挑食不吃猫粮&#xff1f;猫咪挑食应该怎么办&#xff1f;今天为大家分享一个既不让咱宝贝猫咪受罪又可以改善猫咪挑食的方法。 一、为什么猫咪…

深入理解nginx的https sni机制

目录 1. 概述2. 初识sni3. nginx的ssl证书配置指令3.1 ssl_certificate3.2 ssl_certificate_key3.3 ssl_password_file4. nginx源码分析4.1 给ssl上下文的初始化4.2 连接初始化4.3 处理sni回调4.2 动态证书的加载5. 总结阅读姊妹篇: 深入理解nginx的https alpn机制 1. 概述 SN…

Vue+SpringBoot打造音乐偏好度推荐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.1.1 音乐档案模块2.1.2 我的喜好模块2.1.3 每日推荐模块2.1.4 通知公告模块 2.2 用例图设计2.3 实体类设计2.4 数据库设计 三、系统展示3.1 登录注册3.2 音乐档案模块3.3 音乐每日推荐模块3.4 通知公告模…

外包干了6个月,技术退步明显。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;2019年我通过校招踏入了重庆一家软件公司&#xff0c;开始了我的职业生涯。那时的我&#xff0c;满怀热血和憧憬&#xff0c;期待着在这个行业中闯出一片天地。然而&#xff0c;随着时间的推移&#xff0c;我发现自己逐渐陷入…

Dockerfile(1) - FROM 指令详解

FROM 指明当前的镜像基于哪个镜像构建dockerfile 必须以 FROM 开头&#xff0c;除了 ARG 命令可以在 FROM 前面 FROM [--platform<platform>] <image> [AS <name>]FROM [--platform<platform>] <image>[:<tag>] [AS <name>]FROM […

Java+SpringBoot+Vue+MySQL:员工健康管理技术新组合

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

TCP的三次握手和四次挥手 | 查看网络状态

三次握手和四次挥手是在计算机网络中用于建立和终止TCP连接的协议。这两个过程是TCP协议的重要组成部分&#xff0c;确保数据的可靠传输。 三次握手指的是在客户端和服务器之间建立连接时的步骤。具体流程如下&#xff1a; 客户端向服务器发送一个连接请求报文段&#xff08;…