Qt QWidget实现简约美观的加载动画

这篇文章详细介绍了如何使用C++编写并实现六个简单的加载动画,包括SpotsCircle、SpotsShrinkCircle、StickCircle、TubeCircle、TextCircle和TubeBallCircle,这些动画仅需三个文件即可编译运行。
摘要由CSDN通过智能技术生成

😃 给大家分享6个简约的加载动画,这是第一季,后续陆续上架 😃
这是最终效果
在这里插入图片描述
一共只有三个文件,可以直接编译运行

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

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

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

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

    auto* anim3 = new TextCircle("Loading...");
    mainLayout->addWidget(anim3,1,0);

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

    TubeCircle * anim5 = new TubeCircle;
    mainLayout->addWidget(anim5,0,2);

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

    QPushButton * btn = new QPushButton("start");
    mainLayout->addWidget(btn,2,1);
    w.setLayout(mainLayout);
    QObject::connect(btn,&QPushButton::clicked,anim1,&SpotsCircle::exec);
    QObject::connect(btn,&QPushButton::clicked,anim2,&SpotsShrinkCircle::exec);
    QObject::connect(btn,&QPushButton::clicked,anim3,&TextCircle::exec);
    QObject::connect(btn,&QPushButton::clicked,anim4,&StickCircle::exec);
    QObject::connect(btn,&QPushButton::clicked,anim5,&TubeCircle::exec);
    QObject::connect(btn,&QPushButton::clicked,anim6,&TubeBallCircle::exec);
    QObject::connect(btn,&QPushButton::clicked,btn,[=](){
        if(btn->text() == "start") btn->setText("stop");
        else btn->setText("start");
    });
    w.show();
    return a.exec();
}

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

    virtual void exec();
    virtual void start();
    virtual void stop();
protected:
    QPropertyAnimation mAnim;
};

class SpotsShrinkCircle:public LoadingAnimBase{//32个球均匀分布在四周,绕着中心转圈,球越来越小
    Q_OBJECT
    Q_PROPERTY(qreal angle READ angle WRITE setAngle)
public:
    explicit SpotsShrinkCircle(QWidget * parent = nullptr);
    qreal angle()const;
    void setAngle(qreal an);
protected:
    void paintEvent(QPaintEvent *event);
signals:

public slots:
private:
    qreal mAngle;
};

class SpotsCircle : public LoadingAnimBase//8个紧挨着的球绕着中心转圈,每个球大小一样
{
    Q_OBJECT
    Q_PROPERTY(qreal angle READ angle WRITE setAngle)
public:
    explicit SpotsCircle(QWidget *parent = nullptr);

    qreal angle()const;
    void setAngle(qreal an);
protected:
    void paintEvent(QPaintEvent *event);

public slots:
private:
    qreal mAngle;
};
class StickCircle:public LoadingAnimBase//12根小棒分布周围,三根小棒是深色的,其他都是淡色的,深色小棒循环占取淡色小棒的位置
{
    Q_OBJECT
    Q_PROPERTY(qreal angle READ angle WRITE setAngle)
public:
    explicit StickCircle(QWidget* parent = nullptr);
    qreal angle()const;
    void setAngle(qreal an);
    void setShrinkStick(bool shrink);
protected:
    void paintEvent(QPaintEvent *event);

public slots:
private:
    qreal mAngle;
    bool mShrink;
};
class TubeCircle:public LoadingAnimBase //一根管子绕着中心旋转
{
    Q_OBJECT
    Q_PROPERTY(qreal angle READ angle WRITE setAngle)
public:
    explicit TubeCircle(QWidget* parent = nullptr);
    qreal angle()const;
    void setAngle(qreal an);
protected:
    void paintEvent(QPaintEvent *event);

public slots:
private:
    qreal mAngle;
};
class TextCircle:public LoadingAnimBase{ //一串文本绕着中心旋转
    Q_OBJECT
    Q_PROPERTY(qreal angle READ angle WRITE setAngle)
public:
    explicit TextCircle(const QString & txt = "Loading...",QWidget* parent = nullptr);
    qreal angle()const;
    void setAngle(qreal an);
protected:
    void paintEvent(QPaintEvent* event);
private:
    QString mText;
    qreal mAngle;
};

class TubeBallCircle:public LoadingAnimBase //一根封闭的管子,中间有个小球沿着管子滚动
{
    Q_OBJECT
    Q_PROPERTY(qreal angle READ angle WRITE setAngle)
public:
    explicit TubeBallCircle(QWidget* parent = nullptr);
    qreal angle()const;
    void setAngle(qreal an);
protected:
    void paintEvent(QPaintEvent *event);

public slots:
private:
    qreal mAngle;
};


#endif // LOADINGANIMWIDGET_H

//LoadingAnimWidget.cpp
#include "LoadingAnimWidget.h"
#include <QDebug>
#include <QPaintEvent>
#include <QPainter>
LoadingAnimBase::LoadingAnimBase(QWidget* parent):QWidget(parent){}
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();
}
SpotsCircle::SpotsCircle(QWidget *parent) : LoadingAnimBase(parent)
{
    mAnim.setPropertyName("angle");
    mAnim.setTargetObject(this);
    mAnim.setDuration(2000);
    mAnim.setLoopCount(-1);//run forever
    mAnim.setEasingCurve(QEasingCurve::Linear);
    resize(200,200);
    setFixedSize(200,200);
    mAngle = 0;
}
void SpotsCircle::paintEvent(QPaintEvent *event){
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing);
    int x = width();
    int y = height();

    painter.setPen(Qt::NoPen);
    painter.translate(x/2,y/2);
    QColor color = QColor("black");
    qreal alpha = color.alphaF();
    painter.rotate(mAngle);
    for(int i = 0;i<16;++i){//16个小球
        qreal rw = 1.0/8*x;
        qreal r = rw/2;
        painter.setBrush(QBrush(color));
        alpha *= 0.8;
        color.setAlphaF(alpha);
        painter.drawEllipse(0,x/2-rw,r,r);
        auto transform = painter.transform();
        transform.rotate(-2);
        painter.setTransform(transform);
    }
}
qreal SpotsCircle::angle()const{
    return mAngle;
}
void SpotsCircle::setAngle(qreal an){
    mAngle = an;
    update();
}

SpotsShrinkCircle::SpotsShrinkCircle(QWidget *parent) : LoadingAnimBase(parent)
{
    mAnim.setPropertyName("angle");
    mAnim.setTargetObject(this);
    mAnim.setDuration(3000);
    mAnim.setLoopCount(-1);//run forever
    mAnim.setEasingCurve(QEasingCurve::Linear);
    resize(200,200);
    setFixedSize(200,200);
    mAngle = 0;
}
void SpotsShrinkCircle::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 color = QColor("black");
    qreal alpha = color.alphaF();
    painter.rotate(ang);
    qreal rw = 1.0/7*x;
    qreal r = rw/2;
    for(int i = 0;i<12;++i){
        painter.setBrush(QBrush(color));
        alpha *= 0.9;
        color.setAlphaF(alpha);
        painter.drawEllipse(0,x/2-rw,r,r);
        r *= 0.95;
        auto transform = painter.transform();
        transform.rotate(-360/18);
        painter.setTransform(transform);
    }
}
qreal SpotsShrinkCircle::angle()const{
    return mAngle;
}
void SpotsShrinkCircle::setAngle(qreal an){
    mAngle = an;
    update();
}

void StickCircle::setShrinkStick(bool shrink){
    mShrink = shrink;
}
StickCircle::StickCircle(QWidget *parent) : LoadingAnimBase(parent)
{
    mAnim.setPropertyName("angle");
    mAnim.setTargetObject(this);
    mAnim.setDuration(2000);
    mAnim.setLoopCount(-1);//run forever
    mAnim.setEasingCurve(QEasingCurve::Linear);
    resize(200,200);
    setFixedSize(200,200);
    mAngle = 0;
    mShrink = false;
}
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 = QColor("black");
    lightColor.setAlphaF(0.1);

    const int stickw = 10;//小棍子的宽度
    qreal stickl = x / 4;//小棍子的长度

    QColor highlight = QColor("black");
    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);
    }
}
qreal StickCircle::angle()const{
    return mAngle;
}
void StickCircle::setAngle(qreal an){
    mAngle = an;
    update();
}

TextCircle::TextCircle(const QString & txt,QWidget* parent):mText(txt),LoadingAnimBase(parent){
    mAnim.setPropertyName("angle");
    mAnim.setTargetObject(this);
    mAnim.setDuration(2000);
    mAnim.setLoopCount(-1);//run forever
    mAnim.setEasingCurve(QEasingCurve::Linear);
    //resize(200,200);
    setFixedSize(200,200);
    mAngle = 0;
}
qreal TextCircle::angle()const{return mAngle;}
void TextCircle::setAngle(qreal an){
    mAngle = an;
    update();
}

void TextCircle::paintEvent(QPaintEvent* event){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    int x = width();
    int y = height();

    QPen pen("black");
    pen.setWidth(4);
    painter.setPen(pen);

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

    for(int i = 0;i < mText.length();++i){
        const QString s = QString(mText[i]);
        painter.drawText(QRect(-10,y/2-22,20,20),Qt::AlignTop,s);//中下方画一个字符
        painter.rotate(-8);//每个字符之间间距8度
    }
}

TubeCircle::TubeCircle(QWidget *parent) : LoadingAnimBase(parent)
{
    mAnim.setPropertyName("angle");
    mAnim.setTargetObject(this);
    mAnim.setDuration(2000);
    mAnim.setLoopCount(-1);//run forever
    mAnim.setEasingCurve(QEasingCurve::Linear);
    resize(200,200);
    setFixedSize(200,200);
    mAngle = 0;
}
void TubeCircle::paintEvent(QPaintEvent *event){
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing);
    int x = width();
    int y = height();
    qreal ang = mAngle;

    QPen pen(QColor("black"));
    pen.setWidth(x/20);
    pen.setCapStyle(Qt::RoundCap);
    painter.setPen(pen);
    painter.translate(x/2,y/2);
    painter.rotate(ang);
    const int adjust = x/20;
    auto rect = this->rect().adjusted(adjust,adjust,-adjust,-adjust);
    rect.translate(-x/2,-y/2);
    painter.drawArc(rect,30*16,-300*16);

}
qreal TubeCircle::angle()const{
    return mAngle;
}
void TubeCircle::setAngle(qreal an){
    mAngle = an;
    update();
}

TubeBallCircle::TubeBallCircle(QWidget *parent) : LoadingAnimBase(parent)
{
    mAnim.setPropertyName("angle");
    mAnim.setTargetObject(this);
    mAnim.setDuration(2000);
    mAnim.setLoopCount(-1);//run forever
    mAnim.setEasingCurve(QEasingCurve::Linear);
    resize(200,200);
    setFixedSize(200,200);
    mAngle = 0;
}
void TubeBallCircle::paintEvent(QPaintEvent *event){
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing);
    int x = width();
    int y = height();
    qreal ang = mAngle;

    QColor co("gray");
    co.setAlphaF(0.3);
    QPen pen(co);
    const int penw = x/8;
    pen.setWidth(penw);
    pen.setCapStyle(Qt::RoundCap);
    painter.setPen(pen);
    painter.translate(x/2,y/2);
    painter.rotate(ang);
    const int adjust = penw/2;
    auto rect = this->rect().adjusted(adjust,adjust,-adjust,-adjust);
    rect.translate(-x/2,-y/2);
    painter.drawArc(rect,30*16,360*16);//画轨道

    painter.setPen(Qt::NoPen);
    painter.setBrush(QColor("black"));
    painter.drawEllipse(QPoint(0,y/2-penw/2),penw/2,penw/2);//画小球

}
qreal TubeBallCircle::angle()const{
    return mAngle;
}
void TubeBallCircle::setAngle(qreal an){
    mAngle = an;
    update();
}


  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值