Qt动画框架:QVariantAnimation

一、描述

这个类是动画框架的一部分。它用作属性动画的基类。

该类对 QVariants 执行插值。

如果不想将 QVariant 声明为 Qt 属性,则子类化 QVariantAnimation 可以是一种替代方法。但是请注意,在大多数情况下,最好将 QVariant 声明为属性。

并非所有 QVariant 类型都受支持。以下是当前支持的 QVariant 类型列表:

  • int
  • uint
  • double
  • float
  • QLine
  • QLineF
  • QPoint
  • QPointF
  • QSize
  • QSizeF
  • QRect
  • QRectF
  • QColor

如果需要对其他variant类型进行插值,包括自定义类型,则必须自己为这些 variant 类型实现插值。为此,可以为给定类型注册一个内插器函数。该函数接受 3 个参数:起始值、结束值和当前进度。

    QVariant myColorInterpolator(const QColor &start, const QColor &end, qreal progress)
    {
        ...
        return QColor(...);
    }
    ...
    qRegisterAnimationInterpolator<QColor>(myColorInterpolator);

另一种选择是重新实现 interpolated(),它返回被内插值的内插值。

二、属性成员

1、currentValue : const QVariant

此属性保存动画的当前值。开始值和结束值之间的内插值,使用当前时间进行进度。该值本身是从 interpolated() 获得的,它在动画运行时被重复调用。

QVariantAnimation 在当前值改变时调用虚函数 updateCurrentValue() 。这对于需要跟踪更新的子类特别有用。 例如,QPropertyAnimation 使用此函数来为 Qt 属性设置动画。

2、duration : int

此属性描述动画的持续时间(以毫秒为单位)。 默认持续时间为 250 毫秒。

3、easingCurve : QEasingCurve

此属性保存动画的缓和曲线。默认情况下,使用线性缓动曲线插值。

QVariantAnimation 将使用 QEasingCurve::valueForProgress() 将动画的“标准化进度”(currentTime / totalDuration)转换为动画实际使用的有效进度。调用 interpolated() 时的进度就是这种有效的进度。

缓和曲线描述当前值如何随着动画的进展而变化。

4、endValue : QVariant

此属性保存动画的结束值。

5、startValue : QVariant

此属性保存动画的可选起始值。如果省略或将空 QVariant 分配为开始值,则动画将在开始时使用结束的位置。

三、成员函数

1、【信号】void valueChanged(const QVariant &value)

currentValue 发生变化时,会发出此信号。

2、QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress) 

这个虚函数返回变量 from 和 to 之间的线性插值。可以在 QVariantAnimation 的子类中重新实现这个函数,以提供自己的插值算法。

3、QVariant keyValueAt(qreal step) 

返回给定 step 的关键帧值。step 必须在 0 到 1 的范围内。如果 step 没有 KeyValue,则返回无效的 QVariant。

4、QVariantAnimation::KeyValues keyValues() 

返回此动画的关键帧。

5、void setKeyValueAt(qreal step, const QVariant &value)

在给定的 step 用给定的 value 创建一个关键帧。step 必须在 0 到 1 的范围内。 

6、void setKeyValues(const QVariantAnimation::KeyValues &keyValues)

用给定的 keyValues 替换当前的关键帧集。关键帧的步长必须在 0 到 1 的范围内。 

7、void updateCurrentValue(const QVariant &value)

动画的当前值更改时都会调用此虚函数。value 参数是新的当前值。基类实现什么都不做。

四、相关非成员

1、template <typename T> void qRegisterAnimationInterpolator(QVariant (*)(const T &, const T &, qreal) func)

为模板类型 T 注册自定义插值器函数。必须在构造动画之前注册插值器。要取消注册(并使用默认插值器),请将 func 设置为 nullptr。

五、使用示例:自定义类型设置动画的两种方式

5.1、使用 QPropertyAnimation

定义一个结构体 doubleColor ,包含两种颜色,用来填充窗口的上下部分,给它设置动画,观察窗口颜色的变化。

#include <QWidget>

struct doubleColor
{
    doubleColor(QColor frist = Qt::red,QColor second = Qt::blue)
        :fristColor(frist),secondColor(second)
    {}
    QColor fristColor;
    QColor secondColor;

    bool operator !=(const doubleColor & c)
    {
        return (this->fristColor != c.fristColor) || (this->secondColor != c.secondColor);
    }
};
Q_DECLARE_METATYPE(doubleColor)

class Widget : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(doubleColor color MEMBER color)

public:
    Widget(QWidget *parent = nullptr);
    ~Widget()override;
protected:
    void paintEvent(QPaintEvent* e)override;
private:
    doubleColor color{(static_cast<void>(Qt::red),Qt::blue)};
};

 这里将变量导出为属性,见Qt属性系统

#include "widget.h"
#include <QPaintEvent>
#include <QPainter>
#include <QPropertyAnimation>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QPropertyAnimation * animation = new QPropertyAnimation(this, "color");
    animation->setDuration(4000);
    animation->setStartValue(QVariant::fromValue(doubleColor(QColor("#120165"),QColor("#893265"))));
    animation->setEndValue(QVariant::fromValue(doubleColor(QColor("#aa3399"),QColor("#cc9937"))));
    animation->start(QAbstractAnimation::DeleteWhenStopped);//设置播放完了之后animation清除
    connect(animation,&QPropertyAnimation::valueChanged,[this]
    {
        update();
    });
}

Widget::~Widget()
{
}

void Widget::paintEvent(QPaintEvent* e)
{
    auto rect = e->rect();
    QPainter painter(this);
    painter.fillRect(QRect(rect.topLeft(),
                           QPoint(rect.topRight().x(),rect.topRight().x() + (rect.height()/2))),color.fristColor);
    painter.fillRect(QRect(QPoint(rect.topLeft().x(),rect.topLeft().y() + (rect.height()/2)),rect.bottomRight()),color.secondColor);
    QWidget::paintEvent(e);
}
#include "widget.h"
#include <QApplication>
#include <QPropertyAnimation>

QVariant myColorInterpolator(const doubleColor &start, const doubleColor &end, qreal progress)
{
    auto fr = start.fristColor.red() + ((end.fristColor.red() - start.fristColor.red()) * progress);
    auto fg = start.fristColor.green() + ((end.fristColor.green() - start.fristColor.green()) * progress);
    auto fb = start.fristColor.blue() + ((end.fristColor.blue() - start.fristColor.blue()) * progress);

    auto sr = start.secondColor.red() + ((end.secondColor.red() - start.secondColor.red()) * progress);
    auto sg = start.secondColor.green() + ((end.secondColor.green() - start.secondColor.green()) * progress);
    auto sb = start.secondColor.blue() + ((end.secondColor.blue() - start.secondColor.blue()) * progress);

    return QVariant::fromValue(doubleColor(QColor(fr,fg,fb),QColor(sr,sg,sb)));
}

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

    qRegisterAnimationInterpolator<doubleColor>(myColorInterpolator);

    Widget w;
    w.show();

    return a.exec();
}

效果:

 5.2、子类化 QVariantAnimation

#include <QWidget>
#include <QVariantAnimation>

struct doubleColor
{
    doubleColor(QColor frist = Qt::red,QColor second = Qt::blue)
        :fristColor(frist),secondColor(second)
    {}
    QColor fristColor;
    QColor secondColor;

    bool operator !=(const doubleColor & c)
    {
        return (this->fristColor != c.fristColor) || (this->secondColor != c.secondColor);
    }
};
Q_DECLARE_METATYPE(doubleColor)

class doubleColrAnimation : public QVariantAnimation
{
    Q_OBJECT
public:
    doubleColrAnimation(QObject *parent = nullptr)
        :QVariantAnimation(parent)
    {
    }
protected:
    QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress) const override
    {
        doubleColor start = from.value<doubleColor>();
        doubleColor end = to.value<doubleColor>();

        auto fr = start.fristColor.red() + ((end.fristColor.red() - start.fristColor.red()) * progress);
        auto fg = start.fristColor.green() + ((end.fristColor.green() - start.fristColor.green()) * progress);
        auto fb = start.fristColor.blue() + ((end.fristColor.blue() - start.fristColor.blue()) * progress);

        auto sr = start.secondColor.red() + ((end.secondColor.red() - start.secondColor.red()) * progress);
        auto sg = start.secondColor.green() + ((end.secondColor.green() - start.secondColor.green()) * progress);
        auto sb = start.secondColor.blue() + ((end.secondColor.blue() - start.secondColor.blue()) * progress);

        return QVariant::fromValue(doubleColor(QColor(fr,fg,fb),QColor(sr,sg,sb)));
    }
};

class Widget : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(doubleColor color MEMBER color)

public:
    Widget(QWidget *parent = nullptr);
    ~Widget()override;
protected:
    void paintEvent(QPaintEvent* e)override;
private:
    doubleColor color{(static_cast<void>(Qt::red),Qt::blue)};
};
#include "widget.h"
#include <QPaintEvent>
#include <QPainter>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    doubleColrAnimation * animation = new doubleColrAnimation(this);
    animation->setDuration(4000);
    animation->setStartValue(QVariant::fromValue(doubleColor(QColor("#120165"),QColor("#893265"))));
    animation->setEndValue(QVariant::fromValue(doubleColor(QColor("#aa3399"),QColor("#cc9937"))));
    animation->start(QAbstractAnimation::DeleteWhenStopped);//设置播放完了之后animation清除
    connect(animation,&doubleColrAnimation::valueChanged,[this](const QVariant &value)
    {
        color = value.value<doubleColor>();
        update();
    });
}

Widget::~Widget()
{
}

void Widget::paintEvent(QPaintEvent* e)
{
    auto rect = e->rect();
    QPainter painter(this);
    painter.fillRect(QRect(rect.topLeft(),
                           QPoint(rect.topRight().x(),rect.topRight().x() + (rect.height()/2))),color.fristColor);
    painter.fillRect(QRect(QPoint(rect.topLeft().x(),rect.topLeft().y() + (rect.height()/2)),rect.bottomRight()),color.secondColor);
    QWidget::paintEvent(e);
}

效果和上面的图片一致。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值