Qt 简约美观的动画 摆钟风格 第十季

news2024/11/14 21:53:58

😊 今天给大家分享一个摆钟风格的加载动画 😊
效果如下:
在这里插入图片描述
最近工作忙起来了 , 后续再分享其他有趣的加载动画吧.
一共三个文件 , 可以直接编译运行

//main.cpp
#include "LoadingAnimWidget.h"
#include <QApplication>
#include <QGridLayout>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget w;
    w.setWindowTitle("加载动画 第10季");
    QGridLayout * mainLayout = new QGridLayout;

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

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

    auto* anim3 = new CookieMonster;
    mainLayout->addWidget(anim3,0,2);

    auto* anim4 = new StickCircle;
    anim4->setStickColor("lime");
    anim4->setStickWidth(16);
    anim4->setStickLength(32);
    mainLayout->addWidget(anim4,1,0);

    auto* anim5 = new PendulumClock;
    mainLayout->addWidget(anim5,1,1);

    auto* anim6 = new AmpereMeter;
    mainLayout->addWidget(anim6,1,2);

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

//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 StickCircle:public LoadingAnimBase
{
    Q_OBJECT
public:
    explicit StickCircle(QWidget* parent = nullptr);
    void setStickLength(qreal len);
    void setStickWidth(qreal len);
    void setStickColor(const QColor& color);
protected:
    void paintEvent(QPaintEvent *event);
private:
    qreal mStickLen;
    qreal mStickWidth;
    QColor mStickColor;
};
class ThreeMovingZoomingBalls:public LoadingAnimBase{//三个一边移动一边缩放的小球
public:
    ThreeMovingZoomingBalls(QWidget* parent = nullptr);
protected:
    void paintEvent(QPaintEvent*);
};
class FourRotatingFireBall:public LoadingAnimBase{//四个旋转的火球,说他是火球是因为快速转动的时候它有残影,看上去像弧线
public:
    FourRotatingFireBall(QWidget* parent = nullptr);
protected:
    void paintEvent(QPaintEvent*);
};
class CookieMonster:public LoadingAnimBase{//一个不停吃饼干的怪兽
public:
    CookieMonster(QWidget* parent = nullptr);
protected:
    void paintEvent(QPaintEvent*);
};
class PendulumClock:public LoadingAnimBase{//吊钟钟摆
public:
    PendulumClock(QWidget* parent = nullptr);
protected:
    void paintEvent(QPaintEvent*);
};
class AmpereMeter :public LoadingAnimBase{//电流表的指针
public:
    AmpereMeter(QWidget* parent = nullptr);
protected:
    void paintEvent(QPaintEvent*);
};

#endif
//LoadingAnimWidget.cpp
#include "LoadingAnimWidget.h"
#include <QDebug>
#include <QPaintEvent>
#include <QPainter>
#include <QtMath>
#include <QRandomGenerator>
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();
}
StickCircle::StickCircle(QWidget *parent) : LoadingAnimBase(parent),
    mStickLen(-1),mStickWidth(10),mStickColor("black"){}
void StickCircle::setStickLength(qreal len){
    if(len > 0 && len != mStickLen){
        mStickLen = len;
        update();
    }
}
void StickCircle::setStickWidth(qreal len){
    if(len > 0 && len != mStickWidth){
        mStickWidth = len;
        update();
    }
}
void StickCircle::setStickColor(const QColor& color){
    if(color.isValid() && mStickColor != color){
        mStickColor = color;
        update();
    }
}
void StickCircle::paintEvent(QPaintEvent *event){
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing);
    int x = width();
    int y = height();
    qreal ang = mAngle;

    painter.setPen(Qt::NoPen);
    painter.translate(x/2,y/2);
    QColor lightColor = mStickColor;
    lightColor.setAlphaF(0.1);
    const int stickw = mStickWidth;//小棍子的宽度
    qreal stickl = x / 4;//小棍子的长度
    if(mStickLen > 0) stickl = mStickLen;

    QColor highlight = mStickColor;
    const int startIdx = ang / 30;//开头的深色小棍子的索引号
    const int arr[14] = {0,1,2,3,4,5,6,7,8,9,10,11,0,1};
    QList<int> hightlightList{arr[startIdx],arr[startIdx+1],arr[startIdx+2]};
    QList<qreal> alphaList{0.5,0.75,0.99};//三根深色的小棍子的透明度

    for(int i = 0;i < 12;++i){
        if(hightlightList.contains(i)){
            auto hc = highlight;
            hc.setAlphaF(alphaList[0]);
            painter.setBrush(QBrush(hc));
            alphaList.pop_front();
        }
        else {
            painter.setBrush(QBrush(lightColor));
        }
        painter.drawRoundedRect(QRectF(-stickw/2,0.375*y -stickl/2-1,stickw,stickl),stickw/2,stickw/2);
        auto transform = painter.transform();
        transform.rotate(30);
        painter.setTransform(transform);
    }
}
ThreeMovingZoomingBalls::ThreeMovingZoomingBalls(QWidget* parent):LoadingAnimBase(parent){}
void ThreeMovingZoomingBalls::paintEvent(QPaintEvent*){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::NoPen);
    painter.setBrush(QBrush("cadetblue"));
    qreal x = width();
    qreal y = height();
    painter.translate(0,y/2);
    const qreal delta = 0.08*x;
    const qreal minr = 0.02*x;
    for(int i = 0;i < 5;++i){
        qreal ang = mAngle + 90*i;
        qreal posx = ang/360*x;
        if(posx > x) posx -= x;
        qreal r = minr + delta * qSin(M_PI / x * posx);
        painter.drawEllipse(QPointF(posx,0),r,r);
    }
}
FourRotatingFireBall::FourRotatingFireBall(QWidget* parent){}
void FourRotatingFireBall::paintEvent(QPaintEvent*){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    QPen pen;
    pen.setCapStyle(Qt::RoundCap);
    pen.setWidth(12);
    painter.setPen(pen);
    painter.setBrush(Qt::NoBrush);
    const qreal x = width();
    const qreal y = height();
    const qreal r = 0.4*y;
    const qreal maxArc = 30;

    for(int i = 0;i <4;++i){
        painter.resetTransform();
        painter.translate(x/2,y/2);
        painter.rotate(90*i);
        if(i % 2 == 0){
            pen.setColor("lightblue");
            painter.setPen(pen);
        }
        else{
            pen.setColor("lightpink");
            painter.setPen(pen);
        }
        if(mAngle < 30){ //启动火球,画出弧线
            qreal ratio = mAngle / 30;
            painter.drawArc(QRectF(-r,-r,2*r,2*r),16*90,16*-ratio*maxArc);
        }
        else if(mAngle < 330){//转动两圈
            qreal ratio = (mAngle - 30) / 300;
            painter.rotate((720-maxArc)*ratio);
            painter.drawArc(QRectF(-r,-r,2*r,2*r),16*90,16*-maxArc);
        }
        else{//收起弧线
            qreal ratio = (mAngle - 330) / 30;
            painter.drawArc(QRectF(-r,-r,2*r,2*r),16*90,16*(1-ratio)*maxArc);
        }
    }
}
CookieMonster::CookieMonster(QWidget* parent):LoadingAnimBase(parent){}

void CookieMonster::paintEvent(QPaintEvent*){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    const qreal x = width();
    const qreal y = height();
    const qreal r = 0.2*x;
    painter.setPen(Qt::NoPen);
    painter.setBrush(QBrush("royalblue"));
    painter.translate(4,y/2);
    qreal startAngle = 22.5 + 22.5*qSin(M_PI / 90 * mAngle + M_PI/2);
    qreal span = 360 - 2*startAngle;
    painter.drawPie(QRectF(0,-r,2*r,2*r),startAngle*16,span*16);
    painter.setBrush(QBrush("white"));
    painter.drawEllipse(QPointF(r*0.8,-r/2),4,4);

    //画移动的小饼干
    painter.setBrush(QBrush("lightgreen"));
    painter.resetTransform();
    painter.translate(x,y/2);
    qreal ratio = mAngle / 360;
    for(int i = 0;i <3;++i){
        ratio += 0.333;
        if(ratio > 1) ratio -= 1;
        painter.drawEllipse(QPointF( -(x-2*r)*ratio,0 ) , 8,8);
    }
}
PendulumClock::PendulumClock(QWidget* parent):LoadingAnimBase(parent){}

void PendulumClock::paintEvent(QPaintEvent*){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    const qreal x = width();
    const qreal y = height();
    painter.translate(x/2,y/8);
    QPen pen("silver");
    pen.setWidth(4);
    painter.setPen(pen);
    painter.rotate(30*qSin(M_PI/180*mAngle));
    painter.setBrush(QBrush("silver"));
    painter.drawLine(0,0,0,0.6*y);
    painter.translate(0,0.6*y);
    painter.drawEllipse(QPointF(0,0),16,16);
}
AmpereMeter::AmpereMeter(QWidget* parent):LoadingAnimBase(parent){}

void AmpereMeter::paintEvent(QPaintEvent*){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    const qreal x = width();
    const qreal y = height();
    painter.translate(x/2,y*0.6);
    QPen pen("dimgray");
    pen.setWidth(4);
    painter.setPen(pen);
    painter.setBrush(Qt::NoBrush);
    const qreal r = x*0.4;
    //step1 先画一个表框
    painter.drawArc(QRectF(-r,-r,2*r,2*r),0,180*16);
    //step2 再画半圈刻度
    qreal gap = 180 / 14.0;
    painter.rotate(-90);
    for(int i = 1;i <= 13;++i){
        painter.rotate(gap);
        painter.drawLine(0,-r + 6,0,-r + 8);
    }
    //step3 画指针
    painter.resetTransform();
    painter.translate(x/2,y*0.6);
    painter.rotate(80*qSin(M_PI/180*mAngle));
    painter.drawLine(0,0,0,-r*0.7);

}

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

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

相关文章

构建安全的REST API:OAuth2和JWT实践

引言 大家好&#xff0c;我是小黑&#xff0c;小黑在这里跟咱们聊聊&#xff0c;为什么REST API这么重要&#xff0c;同时&#xff0c;为何OAuth2和JWT在构建安全的REST API中扮演着不可或缺的角色。 想象一下&#xff0c;咱们每天都在使用的社交媒体、在线购物、银行服务等等…

Spring框架精髓:带你手写IoC

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

C语言之OJ刷题

今天刷一下题 刷的不多 第一道 链表的回文结构 仔细看这个题它是有限制条件的 首先是时间复杂度和空间复杂度 所以我们并不是用数组去做 但怎么做呢&#xff1f; 思路 既然是判断是否是回文结构&#xff0c;那么我们就找一下他的中间节点 然后将后半段倒置 进行比较…

【简说八股】Redisson的守护线程是怎么实现的

Redisson Redisson 是一个 Java 语言实现的 Redis SDK 客户端&#xff0c;在使用分布式锁时&#xff0c;它就采用了「自动续期」的方案来避免锁过期&#xff0c;这个守护线程我们一般也把它叫做「看门狗」线程。 Redission是一个在Java环境中使用的开源的分布式缓存和分布式锁实…

C2远控Loader红队技巧

inlineHook技术(钩子技术) MessageBoxA C自带弹窗函数 test_MessageBoxA 代码中自定义函数 InlineHook技术&#xff1a;testA原本插入jmp指令跳转到testB&#xff0c;实现testB自定义的函数 实现方式&#xff1a;X86&#xff1a; // 方式一&#xff0c;使用jmp相对地址跳转…

基于springboot音乐翻唱与分享平台源码和论文

1.1研究背景 随着网络不断的普及发展&#xff0c;音乐网站与分享平台依靠网络技术的支持得到了快速的发展&#xff0c;首先要从用户的实际需求出发&#xff0c;通过了解用户的需求开发出具有针对性的首页、音乐资讯、音乐翻唱、在线听歌、留言反馈、个人中心、后台管理、客服功…

ABAP - SALV教程16 合计、小计

虽然ALV的标准状态栏功能就能实现合计、小计、平均值、最大值等这些功能&#xff0c;但用户更希望一进去ALV就希望ALV已经对数量&#xff0c;金额的字段进行合计&#xff0c;小计。SALV实现合计&#xff0c;调用CL_SALV_AGGREGATIONS的ADD_AGGREGATION即可 DATA(lo_aggrs) …

[数据结构]链表OJ--环形链表判断是否有环(快慢指针法)

141. 环形链表 - 力扣&#xff08;LeetCode&#xff09; 这里我采用的是快慢指针法,这是我认为最容易理解的方法,这个方法的思路是这样的. 我们可以定义两个指针一个快一个慢,如果这个链表有环,则快慢指针一定会相遇. 这里我画图举个例子: 我们很明显的可以看出,有环链表,快指…

成功解决git clone遇到的error: RPC failed; curl 16 Error in the HTTP2 framing layer fatal: expected flush af

成功解决git clone遇到的error: RPC failed; curl 16 Error in the HTTP2 framing layer fatal: expected flush af 问题描述解决方案 问题描述 用git的时候可能会遇到这个问题&#xff1a; (base) zhouzikang7443-8x4090-120:~/project$ git clone https://github.com/123/12…

Outlook邮箱IMAP密码怎么填写?账户设置?

Outlook邮箱IMAP密码是什么&#xff1f;Outlook如何设置IMAP&#xff1f; 许多用户会选择通过IMAP协议将邮箱与各种邮件客户端进行连接。而在设置过程中&#xff0c;填写IMAP密码是必不可少的一步。那么&#xff0c;Outlook邮箱的IMAP密码应该如何填写呢&#xff1f;接下来&am…

Matlab 最小二乘插值(曲线拟合)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 在多项式插值时,当数据点个数较多时,插值会导致多项式曲线阶数过高,带来不稳定因素。因此我们可以通过固定幂基函数的最高次数 m(m < n),来对我们要拟合的曲线进行降阶。之前的函数形式就可以变为: 二、实现…

【硬件工程师面经整理13_电容电阻电感等效电路】

1 电容/电阻/电感的等效电路 ①电容的等效电路是由一个电容和一个电阻组成的&#xff0c;其中电阻称为ESR&#xff08;Equivalent Series Resistance&#xff0c;等效串联电阻&#xff09;。在真实情况下&#xff0c;一个电容会被表示成由“一个电容一个电阻一个电感”组合而成…

冒泡排序 和 qsort排序

目录 冒泡排序 冒泡排序部分 输出函数部分 主函数部分 总代码 控制台输出显示 总代码解释 冒泡排序优化 冒泡排序 主函数 总代码 代码优化解释 qsort 排序 qsort 的介绍 使用qsort排序整型数据 使用qsort排序结构数据 冒泡排序 首先&#xff0c;我先介绍我的冒泡…

解决虚拟机启动报错:“End kernel panic - not syncing: attempted to kill the idle task”

原本能正常运行的虚拟机&#xff0c;很长一段时间没用后&#xff0c;今天再次启动&#xff0c;然后就出现下面的问题&#xff1a; 然后走了一些弯路&#xff0c;比如说删除该虚拟机然后新建一个虚拟机&#xff08;问题未解决&#xff09;、直接删除VitualBox重新安装&#xff0…

wordpress外贸独立站

WordPress外贸电商主题 简洁实用的wordpress外贸电商主题&#xff0c;适合做外贸跨境的电商公司官网使用。 https://www.jianzhanpress.com/?p5025 华强北面3C数码WordPress外贸模板 电脑周边、3C数码产品行业的官方网站使用&#xff0c;用WordPress外贸模板快速搭建外贸网…

计算机指令、指令跳转原理

文章目录 前言存储程序型计算机代码怎么变成机器码&#xff1f;解析指令和机器码CPU 是如何执行指令的&#xff1f;CPU中的寄存器 if…else 来看程序的执行和跳转分析 通过 if…else 和 goto 来实现循环 前言 大家好我是jiantaoyab&#xff0c;这是我所总结作为学习的笔记第三篇…

最新版风车IM通讯iosapph5三端源码及视频教程

最新版风车IM通讯iosapph5三端源码及视频教程 1.宝塔环境如下: Nginx 1.20 Tomcat 8 MySQL 8.0 Redis 7 2.放行端口如下&#xff1a; 666 6600 6700 7000&#xff08;用作前端&#xff09; 7001&#xff08;用作后端&#xff09; 3.宝塔数据库添加数据库旁边有个ro…

【大厂AI课学习笔记NO.62】模型的部署

我们历尽千辛万苦&#xff0c;总算要部署模型了。这个系列也写到62篇&#xff0c;不要着急&#xff0c;后面还有很多。 这周偷懒了&#xff0c;一天放出太多的文章&#xff0c;大家可能有些吃不消&#xff0c;从下周开始&#xff0c;本系列将正常更新。 这套大厂AI课&#xf…

随机背景个人引导页源码

随机背景个人引导页源码&#xff0c;每五秒进行淡进淡出切换背景图片&#xff0c;适合作为个人引导页。喜欢的朋友拿去吧 下载地址 https://www.qqmu.com/2357.html

Vue开发实例(九)动态路由实现左侧菜单导航

之前在【Vue开发实例&#xff08;六&#xff09;实现左侧菜单导航】文中实现了菜单的导航&#xff0c;本篇是在那个基础上改造的。 动态路由实现左侧菜单导航 一、动态菜单创建二、根据菜单数据来创建路由三、添加路由已加载标记&#xff0c;省的每次点击菜单都要加载 一、动态…