Qt加载动画

  在做耗时任务时我们总是需要一个加载动画,我们平时都是用gif来做,但是需要找人设计,所以专门自定义一个加载动画

 

// 简单使用
// LoadingAnimation* loader = new LoadingAnimation(this);
// loader->show();

// 详细使用
LoadingAnimation* loader = new LoadingAnimation(this);
loader->setRadius(80);
loader->setCircleColor(QColor(52, 152, 219));
loader->setCircleWidth(8);
loader->setArcSpan(80);
loader->setAnimationDuration(1000);
loader->startAnimation();
loader->setBackgroundColor(Qt::white);
loader->show();

 

.h
// LoadingAnimation.h
#ifndef LOADINGANIMATION_H
#define LOADINGANIMATION_H

#include <QPainter>
#include <QPointer>
#include <QPropertyAnimation>
#include <QWidget>

class LoadingAnimation : public QWidget {
    Q_OBJECT
    Q_PROPERTY(int rotationAngle READ rotationAngle WRITE setRotationAngle)

public:
    explicit LoadingAnimation(QWidget* parent = nullptr);
    ~LoadingAnimation();

    void setCircleColor(const QColor& color);
    void setCircleWidth(int width);
    void setRadius(int radius);
    void setArcSpan(int degrees);
    void setAnimationDuration(int ms);

    // 窗口背景色相关接口(整个控件的背景)
    void setBackgroundColor(const QColor& color);
    QColor backgroundColor() const { return m_backgroundColor; }
    void setBackgroundTransparent(bool transparent);
    bool isBackgroundTransparent() const { return m_backgroundTransparent; }

    void startAnimation();
    void stopAnimation();
    void pauseAnimation();
    void resumeAnimation();

    void setRotationAngle(int angle);
    int rotationAngle() const { return m_rotationAngle; }

protected:
    void paintEvent(QPaintEvent* event) override;

private:
    void updateSize();
    void initAnimation();
    void cleanupAnimation();
    void updateWidgetAttributes();

private:
    int m_rotationAngle;
    QColor m_circleColor;
    int m_circleWidth;
    int m_radius;
    int m_arcSpan;

    // 窗口背景色相关
    QColor m_backgroundColor; // 窗口背景色
    bool m_backgroundTransparent; // 是否透明背景

    // 使用 QPointer 自动检测对象是否被删除
    QPointer<QPropertyAnimation> m_rotationAnimation;
    bool m_animationPaused;
};

#endif

 

.cpp
// LoadingAnimation.cpp
#include "LoadingAnimation.h"

LoadingAnimation::LoadingAnimation(QWidget* parent)
    : QWidget(parent)
    , m_rotationAngle(0)
    , m_circleColor(52, 152, 219) // 蓝色
    , m_circleWidth(6)
    , m_radius(40)
    , m_arcSpan(120)
    , m_backgroundColor(Qt::transparent) // 默认透明背景
    , m_backgroundTransparent(true) // 默认透明
    , m_rotationAnimation(nullptr)
    , m_animationPaused(false)
{
    updateWidgetAttributes();
    updateSize();
    initAnimation();
}

LoadingAnimation::~LoadingAnimation()
{
    cleanupAnimation();
}

void LoadingAnimation::updateWidgetAttributes()
{
    if (m_backgroundTransparent) {
        // 透明背景模式
        setAttribute(Qt::WA_TranslucentBackground);
        setAutoFillBackground(false);
    } else {
        // 不透明背景模式
        setAttribute(Qt::WA_TranslucentBackground, false);
        setAutoFillBackground(true);
    }
}

void LoadingAnimation::initAnimation()
{
    // 先清理旧的动画对象
    cleanupAnimation();

    // 创建新的动画对象,this作为父对象确保自动清理
    m_rotationAnimation = new QPropertyAnimation(this, "rotationAngle");
    m_rotationAnimation->setDuration(1000);
    m_rotationAnimation->setStartValue(0);
    m_rotationAnimation->setEndValue(360);
    m_rotationAnimation->setLoopCount(-1);
    m_rotationAnimation->setEasingCurve(QEasingCurve::Linear);
    m_rotationAnimation->start();
}

void LoadingAnimation::cleanupAnimation()
{
    if (!m_rotationAnimation.isNull()) {
        m_rotationAnimation->stop();
        m_rotationAnimation->deleteLater();
        m_rotationAnimation = nullptr;
    }
}

void LoadingAnimation::updateSize()
{
    int size = m_radius * 2 + m_circleWidth * 2;
    setFixedSize(size, size);
}

void LoadingAnimation::setRotationAngle(int angle)
{
    m_rotationAngle = angle % 360;
    update();
}

void LoadingAnimation::setCircleColor(const QColor& color)
{
    m_circleColor = color;
    update();
}

void LoadingAnimation::setCircleWidth(int width)
{
    if (width <= 0)
        return;
    m_circleWidth = width;
    updateSize();
    update();
}

void LoadingAnimation::setRadius(int radius)
{
    if (radius <= 0)
        return;
    m_radius = radius;
    updateSize();
    update();
}

void LoadingAnimation::setArcSpan(int degrees)
{
    m_arcSpan = qBound(10, degrees, 360);
    update();
}

void LoadingAnimation::setAnimationDuration(int ms)
{
    if (ms <= 0)
        return;
    if (m_rotationAnimation.isNull()) {
        initAnimation();
    }
    m_rotationAnimation->setDuration(ms);
}

// 窗口背景色相关接口实现
void LoadingAnimation::setBackgroundColor(const QColor& color)
{
    m_backgroundColor = color;
    m_backgroundTransparent = (color.alpha() == 0);
    updateWidgetAttributes();
    update();
}

void LoadingAnimation::setBackgroundTransparent(bool transparent)
{
    m_backgroundTransparent = transparent;
    if (transparent) {
        m_backgroundColor = Qt::transparent;
    }
    updateWidgetAttributes();
    update();
}

void LoadingAnimation::startAnimation()
{
    if (m_rotationAnimation.isNull()) {
        initAnimation();
    }

    if (m_rotationAnimation && m_rotationAnimation->state() != QPropertyAnimation::Running) {
        m_rotationAnimation->start();
        m_animationPaused = false;
    }
}

void LoadingAnimation::stopAnimation()
{
    if (!m_rotationAnimation.isNull()) {
        m_rotationAnimation->stop();
        m_animationPaused = false;
    }
}

void LoadingAnimation::pauseAnimation()
{
    if (!m_rotationAnimation.isNull() && m_rotationAnimation->state() == QPropertyAnimation::Running) {
        m_rotationAnimation->pause();
        m_animationPaused = true;
    }
}

void LoadingAnimation::resumeAnimation()
{
    if (!m_rotationAnimation.isNull() && m_animationPaused) {
        m_rotationAnimation->resume();
        m_animationPaused = false;
    }
}

void LoadingAnimation::paintEvent(QPaintEvent* event)
{
    Q_UNUSED(event);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    // 绘制窗口背景色(如果不透明)
    if (!m_backgroundTransparent && m_backgroundColor.alpha() > 0) {
        painter.fillRect(rect(), m_backgroundColor);
    }

    QRect rect = this->rect();
    int centerX = rect.center().x();
    int centerY = rect.center().y();

    QRectF circleRect(centerX - m_radius, centerY - m_radius,
        m_radius * 2, m_radius * 2);

    // 只绘制旋转的圆弧(没有背景圆环)
    QPen arcPen(m_circleColor);
    arcPen.setWidth(m_circleWidth);
    arcPen.setCapStyle(Qt::RoundCap);
    painter.setPen(arcPen);

    int spanAngle = m_arcSpan * 16;
    int startAngle = (m_rotationAngle * 16) % (360 * 16);

    painter.drawArc(circleRect, startAngle, spanAngle);
}

 

posted @ 2026-04-27 15:37  十一的杂文录  阅读(7)  评论(0)    收藏  举报