Qt——功能:序列帧动画

测试环境:win10、Qt Creator 4.11.1、5.14.2版本SDK

 

一、实际效果:

 

二、实现原理:

 

1.序列帧图是将一系列动作放在一张图中展示,一般每幅图大小相等(方便程序处理)。

2.根据每一帧大小定时绘制一幅图。

3.在paintEvent使用QPainter的drawPixmap进行绘制。

 

三、源代码

sequenceFrameAnimation.h

#ifndef SEQUENCEFRAMEANIMATION_H
#define SEQUENCEFRAMEANIMATION_H

#include <QWidget>
#include <QLabel>
#include <QTimer>
#include <QPixmap>

class SequenceFrameAnimation : public QWidget
{
    Q_OBJECT
public:
    enum AnimationSequence
    {
        BeginToEnd,
        EndToBegin,
    };

    explicit SequenceFrameAnimation(QWidget *parent = nullptr);
    ~SequenceFrameAnimation();

    bool setSequenceFrameAnimation(const QString& fileName, int frameWidth, int frameHeight, int frameRate);
    bool setAnimationSequence(AnimationSequence sequence);
    bool setStartFrameIndex(int index = 0);
    void setScaled(const QSize& size);    //设置缩放大小时,长宽必须是每一帧长宽的整数倍
    void setLoopEnabled(bool enabled);    //设置循环播放
    void setSpeedUpEnabled(bool enabled);    //动画启动加速过程
    bool start();    //开始
    void stop();    //结束

signals:

private slots:
    void onTimeout();
    void onSpeedUp();

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    QPixmap m_sequenceFramePixmap;
    QSize m_scaledSize;
    QRect m_currentFrameRect;
    QTimer m_timer;
    QTimer m_speedUpTimer;
    const int m_maxSpeedUpCount;
    int m_currentSpeedUpCount;
    int m_perFrameWidth;
    int m_perFrameHeight;
    int m_frameRate;
    int m_frameIndex;
    int m_row;
    int m_col;
    AnimationSequence m_animationSequence;
    bool m_loop;
    bool m_needSpeedUp;

private:
    int getCurrentSpeedUpTime();
};

#endif // SEQUENCEFRAMEANIMATION_H

sequenceFrameAnimation.cpp

#include "sequenceframeanimation.h"
#include <QPainter>
#include <QStyleOption>
#include <QtMath>
#include <QDebug>

#define SPEEDUP_INTERVAL 10

SequenceFrameAnimation::SequenceFrameAnimation(QWidget *parent) : QWidget(parent),
    m_maxSpeedUpCount(10),
    m_currentSpeedUpCount(1),
    m_perFrameWidth(0),
    m_perFrameHeight(0),
    m_frameRate(0),
    m_frameIndex(0),
    m_animationSequence(BeginToEnd),
    m_loop(false),
    m_needSpeedUp(false)
{
    setWindowFlags(Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint);
    setAttribute(Qt::WA_TranslucentBackground, true);

    connect(&m_timer, &QTimer::timeout, this, &SequenceFrameAnimation::onTimeout);
    connect(&m_speedUpTimer, &QTimer::timeout, this, &SequenceFrameAnimation::onSpeedUp);

    resize(100, 100);
}

SequenceFrameAnimation::~SequenceFrameAnimation()
{

}

bool SequenceFrameAnimation::setSequenceFrameAnimation(const QString& fileName, int frameWidth, int frameHeight, int frameRate)
{
    bool ret = (fileName.isEmpty() ? false : true) && (frameWidth > 0) && (frameHeight > 0) && (frameRate > 0);

    if(ret)
    {
        m_sequenceFramePixmap.load(fileName);
        m_col = m_sequenceFramePixmap.width() / frameWidth;
        m_row = m_sequenceFramePixmap.height() / frameHeight;

        m_perFrameWidth = frameWidth;
        m_perFrameHeight = frameHeight;
        m_frameRate = frameRate;

        m_currentFrameRect = QRect(0, 0, m_perFrameWidth, m_perFrameHeight);

        m_scaledSize = m_sequenceFramePixmap.size();

        resize(m_perFrameWidth, m_perFrameHeight);
    }

    return ret;
}

bool SequenceFrameAnimation::setAnimationSequence(AnimationSequence sequence)
{
    bool ret = (BeginToEnd == sequence) || (EndToBegin == sequence);

    if(ret)
    {
        m_animationSequence = sequence;
    }

    return ret;
}

bool SequenceFrameAnimation::setStartFrameIndex(int index)
{
    bool ret = (0 <= index) && (index <= (m_row * m_col));

    if(ret)
    {
        m_frameIndex = index;

        int x = 0;
        int y = 0;

        if(BeginToEnd == m_animationSequence)
        {
            x = (m_frameIndex % m_col) * m_perFrameWidth;
            y = (m_frameIndex / m_col) * m_perFrameHeight;
            m_currentFrameRect = QRect(x, y, m_perFrameWidth, m_perFrameHeight);
        }
        else
        {
            x = m_sequenceFramePixmap.width() - (m_frameIndex % m_col + 1) * m_perFrameWidth;
            y = m_sequenceFramePixmap.height() - (m_frameIndex / m_col + 1) * m_perFrameHeight;
            m_currentFrameRect = QRect(x, y, m_perFrameWidth, m_perFrameHeight);
        }

        update();
    }

    return ret;
}

void SequenceFrameAnimation::setScaled(const QSize& size)
{
    m_scaledSize = size;
}

void SequenceFrameAnimation::setLoopEnabled(bool enabled)
{
    m_loop = enabled;
}

void SequenceFrameAnimation::setSpeedUpEnabled(bool enabled)
{
    m_needSpeedUp = enabled;
}

bool SequenceFrameAnimation::start()
{
    bool ret = m_sequenceFramePixmap.isNull() ? false : true;

    if(ret)
    {
        m_sequenceFramePixmap = m_sequenceFramePixmap.scaled(m_scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);

        m_perFrameWidth = m_sequenceFramePixmap.width() / m_col;
        m_perFrameHeight = m_sequenceFramePixmap.height() / m_row;
        int x = 0;
        int y = 0;

        if(BeginToEnd == m_animationSequence)
        {
            x = (m_frameIndex % m_col) * m_perFrameWidth;
            y = (m_frameIndex / m_col) * m_perFrameHeight;
            m_currentFrameRect = QRect(x, y, m_perFrameWidth, m_perFrameHeight);
        }
        else
        {
            x = m_sequenceFramePixmap.width() - (m_frameIndex % m_col + 1) * m_perFrameWidth;
            y = m_sequenceFramePixmap.height() - (m_frameIndex / m_col + 1) * m_perFrameHeight;
            m_currentFrameRect = QRect(x, y, m_perFrameWidth, m_perFrameHeight);
        }

        resize(m_perFrameWidth, m_perFrameHeight);

        if(m_needSpeedUp)
        {
            m_currentSpeedUpCount = m_maxSpeedUpCount - 1;
            int time = getCurrentSpeedUpTime();

            m_speedUpTimer.setInterval(time);
            m_speedUpTimer.start();
        }
        else
        {
            m_speedUpTimer.start(m_frameRate);
        }

        update();
    }

    return ret;
}

void SequenceFrameAnimation::stop()
{
    m_timer.stop();
}

void SequenceFrameAnimation::onTimeout()
{
    m_frameIndex++;
    if(m_frameIndex >= (m_row * m_col))
    {
        if(m_loop)
        {
            m_frameIndex = 0;
        }
        else
        {
            m_timer.stop();
            m_frameIndex = 0;
            return;
        }
    }

    int x = 0;
    int y = 0;

    if(BeginToEnd == m_animationSequence)
    {
        x = (m_frameIndex % m_col) * m_perFrameWidth;
        y = (m_frameIndex / m_col) * m_perFrameHeight;
    }
    else
    {
        x = m_sequenceFramePixmap.width() - (m_frameIndex % m_col + 1) * m_perFrameWidth;
        y = m_sequenceFramePixmap.height() - (m_frameIndex / m_col + 1) * m_perFrameHeight;
    }

    m_currentFrameRect = QRect(x, y, m_perFrameWidth, m_perFrameHeight);

    update();
}

void SequenceFrameAnimation::onSpeedUp()
{
    m_currentSpeedUpCount--;
    m_frameIndex++;
    m_frameIndex = m_frameIndex % (m_row * m_col);

    if(m_currentSpeedUpCount <= 0)
    {
        m_speedUpTimer.stop();
        m_timer.start(m_frameRate);
        m_currentSpeedUpCount = m_maxSpeedUpCount;
    }
    else
    {
        int x = 0;
        int y = 0;

        if(BeginToEnd == m_animationSequence)
        {
            x = (m_frameIndex % m_col) * m_perFrameWidth;
            y = (m_frameIndex / m_col) * m_perFrameHeight;
        }
        else
        {
            x = m_sequenceFramePixmap.width() - (m_frameIndex % m_col + 1) * m_perFrameWidth;
            y = m_sequenceFramePixmap.height() - (m_frameIndex / m_col + 1) * m_perFrameHeight;
        }

        m_currentFrameRect = QRect(x, y, m_perFrameWidth, m_perFrameHeight);

        int time = getCurrentSpeedUpTime();
        m_speedUpTimer.setInterval(time);

        update();
    }
}

void SequenceFrameAnimation::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
    painter.drawPixmap(rect(), m_sequenceFramePixmap, m_currentFrameRect);
}

int SequenceFrameAnimation::getCurrentSpeedUpTime()
{
    return (m_frameRate + m_currentSpeedUpCount * SPEEDUP_INTERVAL);
}

 

四、使用示例

#include <QApplication>
#include "groupsucceedwidget.h"


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    SequenceFrameAnimation w1;
    w1.setSequenceFrameAnimation(":/images/voiceSequence.png", 243, 36, 200);   
    w1.setAnimationSequence(SequenceFrameAnimation::BeginToEnd);    //播放顺序:头到尾
    w1.setLoopEnabled(true);    //循环播放
    w1.show();
    w1.start();  

    return a.exec();
}

序列帧图:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值