Qt自定义动画插值函数
这篇文章展示了如何使用自定义的类型实现动画。自定义类型的动画效果使用QVariantAnimation类实现,需要实现一个插值函数。Qt提供了多个接口,主要有如下两种方法:
- 实现QVariant QVariantAnimation::interpolated(const QVariant &from, const QVariant &to, qreal progress) const函数;
- 使用template <typename T> void qRegisterAnimationInterpolator(QVariant (*func)(const T &, const T &, qreal))函数或void QVariantAnimation::registerInterpolator(Interpolator func, int interpolationType)函数注册自定义插值函数。
本例使用第一种方法,实现了一个按钮在两点之间沿着圆弧从起始点运动到结束点的效果。截图示意如下:
头文件。自定义类型是MMyType,我们重写了interpolated(...)函数:
struct MMyType { QPointF pos; }; Q_DECLARE_METATYPE(MMyType); class MDiyAnimation : public QVariantAnimation { Q_OBJECT public: MDiyAnimation(QObject *parent = 0); private: QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress) const override; };
CPP文件:
MDiyAnimation::MDiyAnimation(QObject *parent) : QVariantAnimation(parent) { } QVariant MDiyAnimation::interpolated(const QVariant &from, const QVariant &to, qreal progress) const { MMyType ifrom = from.value<MMyType>(); MMyType ito = to.value<MMyType>(); QPointF ftvec = ifrom.pos - ito.pos; qreal radius = 0.5 * qSqrt(QPointF::dotProduct(ftvec, ftvec)); QPointF center = (ifrom.pos + ito.pos) * 0.5; qreal angle = qAtan2(ftvec.y(), ftvec.x()) + M_PI * progress; MMyType newPos; newPos.pos.setX(center.x() + radius * qCos(angle)); newPos.pos.setY(center.y() + radius * qSin(angle)); return QVariant::fromValue<MMyType>(newPos); }
在主窗口构造函数使用如下。代码中QtTest是主窗口类,ui.pbTest是按钮控件:
QtTest::QtTest(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); MDiyAnimation* ani = new MDiyAnimation(this); connect(ani, &MDiyAnimation::valueChanged, this, [this](const QVariant& v) { QPointF pp = v.value<MMyType>().pos; ui.pbTest->setGeometry(pp.x(), pp.y(), ui.pbTest->width(), ui.pbTest->height()); }); ani->setStartValue(QVariant::fromValue<MMyType>({ ui.pbTest->pos() })); ani->setEndValue(QVariant::fromValue<MMyType>({ QPointF(400, 400) })); ani->setDuration(5000); ani->setLoopCount(-1); ani->start(); }