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 帧动画 (QWidget)_第1张图片

  • 所需资源

    瓯裔

瓯裔

  • 封装后引用

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

#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 
  #include 
  #include 
  • 逻辑流程

    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

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

#include 

/*
* 说明:
*   当前类是针对一张链式图片
*   链式图片默认为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 pixList_;

};

#endif // CUSTOMDYNAMICWIDGET_H

你可能感兴趣的:(Qt,《Qter,必知必会》)