Qt 帧动画 (QWidget)

引言


动画很让人烦恼,在Qt中,已经给出了很多简单的动画,例如 QPropertyAnimation 类实现的动画,但是还不够智能,不是我想要的,相信你也有同感,今天我们就来实现自定义动画类来方便我们日后的开发。

版权所有:瓯裔,转载请注明出处:http://blog.csdn.net/csnd_ayo

简介


操作系统:window7 x64
编程IDE:Qt Creator 4.2.1
Qt版本: 5.0.3 · 5.3.0 · 5.8.0
最后更新:2017年4月14日

示例


效果

  • 效果展示
    为了减小文件,我对gif动画做了一些删减,所以看起来好像有跳帧的现象,其实并没有。

    Qt动画实现效果展示图

  • 所需资源

    瓯裔

瓯裔

  • 封装后引用

    封装后我只需要五行代码即可显示自定义的动画了。

#include "widget.h"
#include "ui_widget.h"
#include "customdynamicwidget.h"
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    dynamicAnima_ = new CustomDynamicWidget(this);
    dynamicAnima_->setAnimation(QPixmap(":/q/level_num.png"),10,100);
    dynamicAnima_->setGeometry(41,41,41,41);
    dynamicAnima_->show();
    // 顺时针播放每帧
    dynamicAnima_->startClockwise();

}

Widget::~Widget()
{
    delete ui;
}

下载

拥有了这个类,你就拥有了所有动画!

代码:下载
图片:下载

原理


  • 实现关联
  #include <QTimer>
  #include <QPainter>
  #include <QWidget>
  • 逻辑流程

    1. 等比例切割传入的图片元素

      • 创建定时器,并关联更新槽
      • 等比例对图片进行切割
    2. 利用了定时器(QTimer) 定时更新界面

      • 定时器被触发
      • 辨别当前帧
      • 若是尾帧辨别是否启用了动画无限循环
      • 修改帧
      • 更新界面
    3. 重写paintEvent函数,利用画家类(QPainter) 完成自绘。

      • 获取当前帧的对应图片
      • 更新当前窗口

实现


逻辑函数

  • 1、等比例切割传入的图片元素
/*
* 设置动画
* setAnimation
* _pix:图片
* _count:图片帧数
* _msec:切换速度 (毫秒 1秒 = 1000毫秒)
*/
void CustomDynamicWidget::setAnimation(const QPixmap &_pix, const short _count, const int _msec) {
    count_ = _count;
    currentIndex_ = 0;

    if (!pixList_.empty()) {
        pixList_.clear();
    }
    else {
        /*  顺时针动画关联  */
        clockTimer_ = new QTimer(this);
        clockTimer_->setInterval(_msec);
        connect(clockTimer_, SIGNAL(timeout()), this, SLOT(updateClockwise()));

        /*  逆时针动画关联  */
        counterclockTimer_ = new QTimer(this);
        counterclockTimer_->setInterval(_msec);
        connect(counterclockTimer_, SIGNAL(timeout()), this, SLOT(updateCounterclockwise()));
    }

    /*  链式动画图标分离  */
    for(short i=0; i != _count; ++i) {
        pixList_.append(_pix.copy(i * (_pix.width() / _count), 0,
                        _pix.width() / _count, _pix.height()));
    }

    currentPix_ = pixList_.at(0);
    this->setGeometry(0,0,currentPix_.width(),currentPix_.height());

    update();

}
  • 2、利用了定时器(QTimer) 定时更新界面
void CustomDynamicWidget::updateClockwise(void) {
    do {
        if (currentIndex_ < count_ && currentIndex_ >= 0) {
            /*  更新帧  */
            currentPix_ = pixList_.at(currentIndex_);
            update();

            /*  判断帧数  */
            if (currentIndex_ >= (count_ - 1)) {
                if(isLoop_) {
                    currentIndex_ = 0;
                    return;
                }
                break;
            }

            /*  跳帧  */
            ++currentIndex_;
            return;
        }
    #ifndef QT_NO_DEBUG
        else {
            qDebug() << __FUNCTION__ << "waring: 错误的下标" << currentIndex_;
        }
    #endif
    } while(false);

    clockTimer_->stop();
    currentIndex_ = 0;
    emit clockwiseFinished();
}
  • 3、重写paintEvent函数,利用画家类(QPainter) 完成自绘。
void CustomDynamicWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.drawPixmap(rect(), currentPix_);
}
  • 头文件
#ifndef CUSTOMDYNAMICWIDGET_H
#define CUSTOMDYNAMICWIDGET_H

/*
* 自定义动画类
* 作者:瓯裔
* 邮箱:727057301@qq.com
* CSDN:http://blog.csdn.net/csnd_ayo
* 创建时间:2017年1月9日 19:34:13
* QT版本:5.0.2 ~ 5.8.0
*/

#include <QWidget>

/*
* 说明:
*   当前类是针对一张链式图片
*   链式图片默认为8帧,默认0.1秒播放一帧
*   可以根据自己需要进行设置与更改
*   进行自动切割,循环播放每一帧
*
* 示例:
*   类内声明 CustomDynamicWidget* dynamicAnima_
*   ui->setupUi(this);
*   dynamicAnima_ = new CustomDynamicWidget(this);
*   dynamicAnima_->setAnimation(QPixmap(":/res/loading.png"),8,100);
*   dynamicAnima_->setGeometry(100,100,300,300);
*   dynamicAnima_->show();
*   // 顺时针播放每帧
*   dynamicAnima_->startClockwise();
*/

class QTimer;
class CustomDynamicWidget : public QWidget
{
    Q_OBJECT
public:

    explicit CustomDynamicWidget(QWidget *parent = 0);
    /*
    * 设置动画图标
    * 函数名:setAnimation
    * 参数 _pix:图标实例
    * 参数 _count:图标实例动画帧数
    * 参数 _msec:动画切帧速度 (毫秒级)
    */
    void setAnimation(const QPixmap& _pix, const short _count = 8, const int _msec = 100);

    /*  开始动画(顺时针)  */
    void startClockwise(void);
    /*  开始动画(逆时针)  */
    void startCounterclockwise(void);
    /*  停止动画  */
    void stop(void);
    /*  设置动画无限循环  */
    void setLoop(const bool _isLoop = false) { isLoop_ = _isLoop; }

signals:

    /*  顺时针动画结束  */
    void clockwiseFinished(void);
    /*  逆时针动画结束  */
    void counterclockwiseFinished(void);

private slots:

    /*  顺时针动画槽  */
    void updateClockwise(void);
    /*  逆时针动画槽  */
    void updateCounterclockwise(void);

protected:

    void paintEvent(QPaintEvent *);

private:

    /*  动画(是否无限循环)  */
    bool isLoop_;
    /*  图标列表数量  */
    short count_;
    /*  当前展示的图标下标  */
    short currentIndex_;
    /*  控制顺时针槽定时器  */
    QTimer *clockTimer_;
    /*  控制逆时针槽定时器  */
    QTimer *counterclockTimer_;
    /*  当前展示的图标  */
    QPixmap currentPix_;
    /*  图标列表  */
    QList<QPixmap> pixList_;

};

#endif // CUSTOMDYNAMICWIDGET_H
  • 9
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Qt中使用OpenGL和Assimp加载骨骼动画,需要进行以下步骤: 1. 在Qt中使用OpenGL:首先,需要使用Qt的OpenGL模块来创建OpenGL窗口和上下文。可以使用Qt自带的QGLWidget类或者QOpenGLWidget类来创建OpenGL窗口。然后,需要在OpenGL上下文中加载Assimp导入的模型和动画数据。 2. 加载Assimp导入的模型:使用Assimp库导入模型文件,并将所有顶点数据存储在内存中。Assimp库还提供了一些函数来访问模型的骨骼和动画数据。 3. 加载骨骼动画:使用Assimp库提供的函数来加载骨骼动画数据。这些数据通常包括关键帧和骨骼层次结构。可以使用这些数据来计算每个骨骼在每个时间步长中的变换矩阵。 4. 动画播放:将每个骨骼的变换矩阵应用于每个顶点,以在每个时间步长中更新动画。可以使用OpenGL的顶点着色器来执行此操作。 以下是一些代码示例,演示如何在Qt中加载Assimp导入的模型和动画数据,并将其渲染到OpenGL窗口中: ```cpp #include <QOpenGLWidget> #include <QOpenGLFunctions> #include <assimp/Importer.hpp> #include <assimp/scene.h> #include <assimp/postprocess.h> class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions { public: MyOpenGLWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent) { } void initializeGL() override { initializeOpenGLFunctions(); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); Assimp::Importer importer; const aiScene* scene = importer.ReadFile("model.dae", aiProcess_Triangulate | aiProcess_FlipUVs); // Load mesh data into VBOs ... // Load bone data into VBOs ... // Load animation data into VBOs ... } void paintGL() override { glClear(GL_COLOR_BUFFER_BIT); // Update animation ... // Render mesh ... } }; ``` 在上面的示例中,`initializeGL()`函数将加载模型和动画数据,并将它们存储在OpenGL缓冲区中。`paintGL()`函数将更新动画并呈现模型。这些步骤的具体实现将取决于您的应用程序需求和Assimp库的版本。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值