鱼C论坛

 找回密码
 立即注册
查看: 7081|回复: 0

[技术原创] Qt实现自定义QWidget动画控件 - 动画基础(一)

[复制链接]
发表于 2017-4-16 22:54:20 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 miss陈 于 2017-4-16 22:59 编辑

引言

动画很让人烦恼,在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>
逻辑流程

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

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

定时器被触发
辨别当前帧
若是尾帧辨别是否启用了动画无限循环
修改帧
更新界面
重写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
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 19:35

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表