アニメーション・フレームワーク
アニメーションフレームワークは、GUI 要素をアニメーションさせる簡単な方法を提供します。QObjectフレームワークによって提供される機能のほとんどは、Qt Quick でも利用可能で、宣言的な方法でアニメーションを定義することができます。
この概要では、QObject や GUI 要素のアニメーションに使用される一般的なテクニックを示す例とともに、フレームワークのアーキテクチャを説明します。
アニメーションのアーキテクチャ
次の図は、フレームワークが提供する最も重要なクラスを示したものです:
これには、アニメーションに必要な基礎を提供するQAbstractAnimation クラスが含まれます。このクラスは、フレームワークがサポートするすべてのアニメーションの汎用プロパティを定義します。例えば、アニメーションを開始、停止、一時停止する機能などです。また、このクラスは時間変更の通知も受け取ります。
フレームワークはさらに、QVariantAnimation とQAnimationGroup クラスを提供し、これらはその基本ケースであるQAbstractAnimation をベースにしています。QPropertyAnimation QObjectこのクラスは、イージング曲線を使用してプロパティ値の補間を行います。このクラスは、イージングカーブを使用して、プロパティ値の補間を行います。これらを使用すると、アニメートできる Qt プロパティ値を持つQObject クラスが必要になります。
注意: アニメーションさせるターゲット・オブジェクトは、QObject またはそのサブクラスである必要があります。これは、アニメーションフレームワークが、アニメーション対象のオブジェクトに関するすべての情報をメタオブジェクトシステムに依存しているためです。
複雑なアニメーションは、QAbstractAnimations のツリー構造を構築することで構築できます。ツリーとは、他のアニメーションを含むQAnimationGroup のことです。これらのアニメーショングループには、QParallelAnimationGroup やQSequentialAnimationGroup のように、異なるグループやアニメーションを表すサブグループを含めることもできます。
舞台裏では、すべてのアニメーションはグローバルタイマーによって制御され、グローバルタイマーは実行中のすべてのアニメーションについてupdates 。
これらの個々のクラスの詳細な情報とフレームワークでの役割については、それらのドキュメントを参照してください。
フレームワークによって提供されるクラス
これらのクラスは、単純なアニメーションと複雑なアニメーションの両方を作成するために必要なインフラストラクチャを提供します。
すべてのアニメーションの基本 | |
アニメーションのグループのための抽象基底クラス | |
アニメーションを制御するためのイージングカーブ | |
アニメーションの並列グループ | |
QSequentialAnimationGroupの一時停止 | |
Qt プロパティのアニメーション | |
シーケンシャルアニメーショングループ | |
アニメーションを制御するタイムライン | |
アニメーションの基底クラス |
Qt プロパティのアニメーション
QPropertyAnimation クラスは Qt プロパティを補間できるので、よく使われます。実際、そのスーパークラスであるQVariantAnimationは、updateCurrentValue() の抽象的な実装を提供し、valueChanged signal で値を変更しない限り、値は変更されません。
フレームワークでは、Qt の既存のクラスの Qt プロパティをアニメーション化することができます。例えば、QWidget クラスは、QGraphicsViewに埋め込むことができ、その境界や色などのプロパティを持っています。次の例は、QPushButton ウィジェットをアニメーション化する方法を示しています:
#include <QApplication> #include <QPushButton> #include <QPropertyAnimation> class MyButtonWidget : public QWidget { public: MyButtonWidget(QWidget *parent = nullptr); }; MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) { QPushButton *button = new QPushButton(tr("Animated Button"), this); QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this); anim->setDuration(10000); anim->setStartValue(QPoint(0, 0)); anim->setEndValue(QPoint(100, 250)); anim->start(); } int main(int argc, char *argv[]) { QApplication a(argc, argv); MyButtonWidget buttonAnimWidget; buttonAnimWidget.resize(QSize(800, 600)); buttonAnimWidget.show(); return a.exec(); }
この例では、QPushButton のpos
Qt プロパティをアニメーション化し、画面の左上隅から終了位置 (250, 250) までを 10 秒 (10000 ミリ秒) で移動します。
これは、開始値と終了値の間でアニメーションの速度を制御するために線形補間法を使用しています。開始値と終了値の間に別の値を追加して、それらがどのように補間されるかを試してみてください。今度はQPropertyAnimation::setKeyValueAt関数を使用してこれらの値を追加します:
... anim->setDuration(10000); anim->setKeyValueAt(0, QPoint(0, 0)); anim->setKeyValueAt(0.8, QPoint(250, 250)); anim->setKeyValueAt(1, QPoint(0, 0)); ...
この例では、アニメーションは8秒でボタンを(250, 250)に移動させ、残りの2秒で元の位置に戻します。この例では、8秒後にボタンが(250, 250)に移動し、残りの2秒後に元の位置に戻ります。ボタンの移動は、これらの点間で線形補間されます。
Qtのプロパティとして宣言されていないQObject の値も、セッター・メソッドがあればアニメーションさせることができます。このような場合は、値を含むクラスから新しいクラスを派生させ、その値の Qt プロパティをセッターとともに追加します。
注意: 各Qtプロパティにはゲッターも必要なので、ゲッターが定義されていない場合は用意する必要があります。
class MyGraphicsRectItem : public QObject, public QGraphicsRectItem { Q_OBJECT Q_PROPERTY(QPointF pos READ pos WRITE setPos) };
この例では、MyGraphicsRectItem
は、QGraphicsRectItem とQObject から派生し、pos
プロパティを定義しています。QGraphicsRectItem がpos
プロパティを提供していなくても、アイテムのpos
をアニメーション化することができます。
Qt のプロパティ・システムの概要については、「Qt のプロパティ・システム」を参照してください。
アニメーションとグラフィックス・ビュー・フレームワーク
QPropertyAnimation は、 を継承していない をアニメーション化するために使用することもできます。このような場合、アニメートさせたいグラフィック・アイテムからクラスを派生させます。この派生クラスは、 で を使用できるように、 も継承する必要があります:QObject QGraphicsItem QGraphicsItem QPropertyAnimation QObject
class Pixmap : public QObject, public QGraphicsPixmapItem { Q_OBJECT Q_PROPERTY(QPointF pos READ pos WRITE setPos) ... }
注: すでにQObject であるQGraphicsWidget から派生させることもできます。
前のセクションで説明したように、アニメートさせたいプロパティを定義する必要があります。派生クラスは、メタオブジェクトシステムが要求するように、まずQObject を継承する必要があります。
曲線の緩和
QPropertyAnimation は、開始と終了のプロパティ値の間で線形補間を行います。アニメーションにさらにキー値を追加するだけでなく、イージングカーブを選択することで、パスを変更することなく、補間のスピードを0と1の間でコントロールすることができます。
MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) { QPushButton *button = new QPushButton(tr("Animated Button"), this); QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this); anim->setDuration(10000); anim->setStartValue(QPoint(0, 0)); anim->setEndValue(QPoint(100, 250)); anim->setEasingCurve(QEasingCurve::OutBounce); anim->start(); }
この例では、アニメーションはbutton
をボールのように弾ませる曲線に従っています。QEasingCurve は、QEasingCurve::Type enum から選択できる曲線の大規模なコレクションを提供しています。利用できない別の曲線を使いたい場合は、自分で実装してQEasingCurve に登録してください。
アニメーションのグループ化
アプリケーションには、複数のアニメーションが含まれていることがよくあります。例えば、複数のグラフィック・アイテムを同時に動かしたい場合や、順番に動かしたい場合などです。
QAnimationGroupのサブクラスであるQSequentialAnimationGroup とQParallelAnimationGroupは、他のアニメーショ ンのコンテナであり、これらのアニメーションを順番に、または並列にアニ メーションさせることができます。QAnimationGroup はプロパティをアニメートしないが、定期的に時間変化の通知を受ける。これによって、時間の変化をアニメーション・グループに転送し、アニメーション・グループがアニメーションを再生するタイミングを制御することができます。
以下の2つの例では、QSequentialAnimationGroup とQParallelAnimationGroup の両方を使用しています:
MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) { QPushButton *bonnie = new QPushButton(tr("Bonnie"), this); QPushButton *clyde = new QPushButton(tr("Clyde"), this); QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this); anim1->setDuration(3000); anim1->setStartValue(QPoint(0, 0)); anim1->setEndValue(QPoint(100, 250)); QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this); anim2->setDuration(3000); anim2->setStartValue(QPoint(100, 250)); anim2->setEndValue(QPoint(500, 500)); QParallelAnimationGroup *parallelAnim = new QParallelAnimationGroup; parallelAnim->addAnimation(anim1); parallelAnim->addAnimation(anim2); parallelAnim->start(); }
並列グループは、同時に複数のアニメーションを再生します。そのstart ()関数は、グループの一部であるすべてのアニメーションを開始します。
MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) { QPushButton *bonnie = new QPushButton(tr("Bonnie"), this); QPushButton *clyde = new QPushButton(tr("Clyde"), this); QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "pos", this); anim1->setDuration(3000); anim1->setStartValue(QPoint(0, 0)); anim1->setEndValue(QPoint(100, 250)); QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "pos", this); anim2->setDuration(3000); anim2->setStartValue(QPoint(0, 0)); anim2->setEndValue(QPoint(200, 250)); QSequentialAnimationGroup *sequenceAnim = new QSequentialAnimationGroup; sequenceAnim->addAnimation(anim1); sequenceAnim->addAnimation(anim2); sequenceAnim->start(); }
その名前が示すように、QSequentialAnimationGroup はアニメーションを順番に再生します。前のアニメーションが終了した後、リストの次のアニメーションを開始します。
グループはアニメーションそのものなので、別のグループに追加することもできます。このようにして、アニメーションツリーを構築し、アニメーションがいつ再生されるかを定義します。
オブジェクトの所有権
QPropertyAnimation は常に、その寿命をコントロールする親を持つべきです。典型的なアプリケーションでは、いくつかのアニメーションがグループ化され、アニメーショングループがそれらのアニメーションの所有権を持ちます。独立したQPropertyAnimation には、その寿命をコントロールする親を明示的に割り当てる必要があります。次の例では、独立したQPropertyAnimation が、QApplication インスタンスを親として持っていることがわかります:
#include <QApplication> #include <QPushButton> #include <QPropertyAnimation> class MyButtonWidget : public QWidget { public: MyButtonWidget(QWidget *parent = nullptr); }; MyButtonWidget::MyButtonWidget(QWidget *parent) : QWidget(parent) { QPushButton *button = new QPushButton(tr("Animated Button"), this); QPropertyAnimation *anim = new QPropertyAnimation(button, "pos", this); anim->setDuration(10000); anim->setStartValue(QPoint(0, 0)); anim->setEndValue(QPoint(100, 250)); anim->start(); } int main(int argc, char *argv[]) { QApplication a(argc, argv); MyButtonWidget buttonAnimWidget; buttonAnimWidget.resize(QSize(800, 600)); buttonAnimWidget.show(); return a.exec(); }
注: アニメーションを開始するときにdelete policy を選択することで、アニメーションの寿命をコントロールすることもできます。
本ドキュメントに含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。