qt序列帧读取

 描述:

        有时候ui给我们的动画是一序列的图片,播放动画需要一张一张图片读取,显得有点麻烦,存储的资源目录也显得比较凌乱。为解决这个问题,又不想使用gif,可以使用如下自定义序列帧播放组件,一次读取,通过计算当前帧的位置从内存读取当前帧。可以控制顺时针/逆时针播放、是否循环、播放每一帧的事件间隔。希望对大家有用。

.hpp文件

#include <QWidget>
#include <QPointer>

class QTimer;
class FramePlayWidget : public QWidget{
    Q_OBJECT
public:
    explicit FramePlayWidget (QWidget* parent = nullptr);

    virtual ~FramePlayWidget ();

    /**
     ************************************************************
     * @brief:      设置动画图标
     * @param[in]:  图标实例
     * @param[in]:  图标实例动画帧数
     * @return:     
     ************************************************************
     */
    void SetAnimation(const QPixmap& pix, int count = 1);

    /**
     ************************************************************
     * @brief:      设置定时器时间间隔(毫秒级)
     ************************************************************
     */
    void SetInterval(int msec);

    /**
     ************************************************************
     * @brief:      开始动画   
     ************************************************************
     */
    void Start();

    /**
     ************************************************************
     * @brief:      停止动画    
     ************************************************************
     */
    void Stop();

    /**
     ************************************************************
     * @brief:      设置是否循环播放
     * @param[in]:  isLoop : true 循环播放, false 不循环播放   
     ************************************************************
     */
    void SetLoop(bool isLoop);

    /**
     ************************************************************
     * @brief:      设置是否顺时针播放
     * @param[in]:  bClockwise: true 顺时针, false: 逆时针  
     ************************************************************
     */
    void SetClockwise(bool bClockwise);

protected:

    /**
     ************************************************************
     * @brief: 初始化ui
     ************************************************************
     */
    void InitUi();


    /**
     ************************************************************
     * @brief: 信号绑定
     ************************************************************
     */
    void ConnectSignals();

signals:

    /**
     ************************************************************
     * @brief: 播放完成信号    
     ************************************************************
     */
    void sigPlayFinished();

private slots:
    /**
     ************************************************************
     * @brief:  更新帧槽函数  
     ************************************************************
     */
    void slotUpdateFrame();

protected:

    void paintEvent(QPaintEvent*) override;

private:
    bool                    m_bClockwise;           // 是否顺时针播放
    bool                    m_bIsLoop;              // 是否循环
    int                     m_nFrameCount;          // 帧数
    int                     m_nCurrentIndex;        // 当前展示图片下标
    int                     m_nInterval;            // 时间间隔(毫秒)
    QPointer<QTimer>        m_pClockTimer;          // 更新定时器
    QPixmap                 m_currentPix;           // 当前帧
    QPixmap                 m_originalPix;          // 原始位图
    QList<QPixmap>          m_pixList;              // 位图列表
};

.cpp文件

#include "FramePalyWidget.hpp"
#include <QTimer>
#include <QPainter>

FramePlayWidget::FramePlayWidget (QWidget* parent)
    : QWidget(parent)
    , m_bIsLoop(true)
    , m_bClockwise(true){
    InitUi();
    ConnectSignals();
}

FramePlayWidget::~FramePlayWidget() {

    
}

/**
 ************************************************************
 * @brief: 初始化ui
 ************************************************************
 */
void FramePlayWidget::InitUi(){
    m_pClockTimer = new QTimer(this);
    m_pClockTimer->setInterval(10);
}

/**
 ************************************************************
 * @brief: 信号绑定
 ************************************************************
 */
void FramePlayWidget::ConnectSignals() {
    connect(m_pClockTimer, SIGNAL(timeout()), this, SLOT(slotUpdateFrame()));
}


/**
 ************************************************************
 * @brief:      设置定时器时间间隔(毫秒级)
 ************************************************************
 */
void FramePlayWidget::SetInterval(int msec) {
    if (m_pClockTimer) {
        m_pClockTimer->setInterval(msec);
    }
}

/**
 ************************************************************
 * @brief:      设置动画图标
 * @param[in]:  图标实例
 * @param[in]:  图标实例动画帧数
 * @param[out]: 动画切帧速度 (毫秒级)
 * @return:
 ************************************************************
 */
void FramePlayWidget::SetAnimation(const QPixmap& pix, int count) {
    m_nFrameCount = count;
    m_nCurrentIndex = 0;

    if(m_nFrameCount <= 0) {
        return;
    }

    if (!m_pixList.empty()) {
        m_pixList.clear();
    }
    
    if(m_pClockTimer->isActive()){
        m_pClockTimer->stop();
    }

    // 帧获取
    for (short i = 0; i < count; ++i) {
        m_pixList.append(pix.copy(i * (pix.width() / count), 0,
                         pix.width() / count, pix.height()));
    }

    m_currentPix = m_pixList.at(0);
    update();

}

/**
 ************************************************************
 * @brief:      开始动画
 ************************************************************
 */
void FramePlayWidget::Start() {
    if(m_pClockTimer){
        if (m_pClockTimer->isActive()) {
            m_pClockTimer->stop();
        }
        m_pClockTimer->start();
    }
}

/**
 ************************************************************
 * @brief:      停止动画
 ************************************************************
 */
void FramePlayWidget::Stop() {
    if (m_pClockTimer) {
        m_pClockTimer->stop();
    }
}

/**
 ************************************************************
 * @brief:      设置是否循环播放
 * @param[in]:  isLoop : true 循环播放, false 不循环播放
 ************************************************************
 */
void FramePlayWidget::SetLoop(bool isLoop) {
    m_bIsLoop = isLoop; 
}

/**
 ************************************************************
 * @brief:      设置是否顺时针播放
 * @param[in]:  bClockwise: true 顺时针, false: 逆时针
 ************************************************************
 */
void FramePlayWidget::SetClockwise(bool bClockwise) {
    m_bClockwise = bClockwise;
}

/**
 ************************************************************
 * @brief:  更新帧槽函数
 ************************************************************
 */
void FramePlayWidget::slotUpdateFrame() {
    if (m_nCurrentIndex < m_nFrameCount && m_nCurrentIndex >= 0) {
        //  更新帧
        m_currentPix = m_pixList.at(m_nCurrentIndex);
        update();

        if (m_bClockwise) {
            //  判断帧数
            if (m_nCurrentIndex >= (m_nFrameCount - 1)) {
                if (m_bIsLoop) {
                    m_nCurrentIndex = 0;
                    return;
                }
                m_pClockTimer->stop();
                m_nCurrentIndex = 0;
                emit sigPlayFinished();
                return;
            }

            //  跳帧
            ++m_nCurrentIndex;
        }
        else {
            //  判断帧数
            if (m_nCurrentIndex <= 0) {
                if (m_bIsLoop) {
                    m_nCurrentIndex = m_nFrameCount - 1;
                    return;
                }
                m_pClockTimer->stop();
                m_nCurrentIndex = m_nFrameCount - 1 ;
                emit sigPlayFinished();
                return;
            }
            //  跳帧
            --m_nCurrentIndex;
        }
        
    }
}

void FramePlayWidget::paintEvent(QPaintEvent*) {
    QPainter painter(this);
    painter.drawPixmap(rect(), m_currentPix);
}

使用样例:

    FramePlayWidget* m_pTestAnimal = new FramePlayWidget(this);
    m_pTestAnimal ->setFixedSize(70, 140);
    m_pTestAnimal ->SetAnimation(QPixmap(":res/img/test/test.png"), 50);
    m_pTestAnimal ->SetClockwise(true);        // 顺时针读取
    m_pTestAnimal ->SetInterval(40);           // 帧读取事件间隔
    m_pTestAnimal ->SetLoop(false);            // 是否循环

    connect(m_pTestAnimal , &FramePalyWidget::sigPlayFinished,
            this, [&](){
        // TODO finished
    });

序列帧合成地址:

地址1:https://www.toptal.com/developers/css/sprite-generator

地址2:https://cdkm.com/cn/merge-image

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt中,可以使用QXmlStreamReader类来读取XML文件,然后将XML数据反序列化为对象。 以下是一个简单的示例代码,演示如何使用QXmlStreamReader读取XML文件,并将XML数据反序列化为一个Person对象: ```c++ #include <QFile> #include <QXmlStreamReader> #include <QXmlStreamAttributes> #include <QDebug> class Person { public: QString name; int age; // 反序列化函数 bool fromXml(QXmlStreamReader& reader) { while (!reader.atEnd()) { QXmlStreamReader::TokenType token = reader.readNext(); if (token == QXmlStreamReader::StartElement) { QStringRef name = reader.name(); if (name == "name") { name = reader.readElementText(); this->name = name.toString(); } else if (name == "age") { QStringRef ageStr = reader.readElementText(); bool ok; int age = ageStr.toInt(&ok); if (!ok) { return false; } this->age = age; } } else if (token == QXmlStreamReader::EndElement) { QStringRef name = reader.name(); if (name == "person") { return true; } } } return false; } }; int main() { // 打开XML文件 QFile file("example.xml"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qCritical() << "Failed to open file!"; return -1; } // 创建XML读取器 QXmlStreamReader reader(&file); // 反序列化Person对象 Person person; if (!person.fromXml(reader)) { qCritical() << "Failed to parse XML file!"; return -1; } // 输出Person对象的属性 qDebug() << "Name: " << person.name; qDebug() << "Age: " << person.age; // 关闭文件和XML读取器 file.close(); reader.clear(); return 0; } ``` 这个示例代码会读取名为“example.xml”的XML文件,并将XML数据反序列化为一个Person对象。如果XML文件格式不正确,程序会输出错误信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值