[translation] Qt animation framework

Posted by khjart on Sat, 18 Dec 2021 12:20:56 +0100

The animation framework is designed to provide a simple way to create an animated and smooth GUI. Through the animation Qt attribute, the framework provides a lot of freedom for animation widgets and other qobjects. The frame can also be used with the drawing view frame. Many of the concepts available in the animation framework are also available in Qt Quick, which provides a declarative way to define animation. Most of the knowledge about animation framework can be applied to Qt Quick.

1, Animation architecture

The following figure shows the most important classes in the animation framework.

QAbstractAnimation is the ancestor of all animation. It represents the basic properties common to all animations in the framework, especially the ability to start, stop and pause animation. It also receives notification of time changes.

The animation framework further provides the QPropertyAnimation class, This class inherits QVariantAnimation and animates the Qt attribute (the attribute is part of the Qt meta object system). This class uses the jog curve to interpolate the attribute. Therefore, when you want to animate a value, you can declare it as an attribute and make the class a subclass of QObject, which makes it free to animate existing widgets and other qobjects.

You can build complex animations by building the tree structure of QAbstractAnimations. The tree is built using QAnimationGroups, which serve as containers for other animations. Note that groups are subclasses of QAbstractAnimation, so the group itself can contain other groups.

Behind the scenes, the animation is controlled by a global timer that sends updates to all animations being played.

2, Class list

  • QAbstractAnimation
  • QAnimationGroup
  • QEasingCurve
  • QParallelAnimationGroup
  • QPauseAnimation
  • QPropertyAnimation
  • QSequentialAnimationGroup
  • QTimeLine
  • QVariantAnimation

3, Qt attribute animation

QPropertyAnimation class can interpolate Qt attribute.

One of the main reasons for choosing to animate the Qt attribute is that it is free to animate existing classes in the Qt API. Take a small example:

QPushButton button("Animated Button");
button.show();

QPropertyAnimation animation(&button, "geometry");
animation.setDuration(10000);
animation.setStartValue(QRect(0, 0, 100, 30));
animation.setEndValue(QRect(250, 250, 100, 30));

animation.start();

This code will move the button from the upper left corner of the screen to the position (250, 250) in 10 seconds (10000 milliseconds).

The above example interpolates linearly between the start and end values. You can also set a value between the start value and the end value. The interpolation will then pass through these points:

QPushButton button("Animated Button");
button.show();

QPropertyAnimation animation(&button, "geometry");
animation.setDuration(10000);

animation.setKeyValueAt(0, QRect(0, 0, 100, 30));
animation.setKeyValueAt(0.8, QRect(250, 250, 100, 30));
animation.setKeyValueAt(1, QRect(0, 0, 100, 30));

animation.start();

The animation will take the button to (250, 250) in 8 seconds, and then move it back to its original position in the remaining 2 seconds. The motion is interpolated linearly between these points.

You can also animate the value of QObject not declared as Qt attribute. The only requirement is that this property has a setter. Note that each Qt attribute requires a getter. For example:

    Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry)

For Qt attribute system, see: Qt attribute system.

4, Animation and graphics view frames

You can also use QPropertyAnimation when you want to animate QGraphicsItems. However, QGraphicsItem does not inherit QObject. You need to use QGraphicsObject or QGraphicsWidget instead, or inherit QObject and QGraphicsItem at the same time.

class Pixmap : public QObject, public QGraphicsPixmapItem
{
    Q_OBJECT
    Q_PROPERTY(QPointF pos READ pos WRITE setPos)
    ...

Note that QObject must be the first inherited class because the meta object system needs to do so.

5, Transition curve

QPropertyAnimation performs interpolation between the start and end attribute values. In addition to adding more keys to the animation, you can also use spirals. A spiral describes a function that controls how fast the interpolation should be between 0 and 1, which is useful if you want to control the speed of the animation without changing the interpolation path.

QPushButton button("Animated Button");
button.show();

QPropertyAnimation animation(&button, "geometry");
animation.setDuration(3000);
animation.setStartValue(QRect(0, 0, 100, 30));
animation.setEndValue(QRect(250, 250, 100, 30));

animation.setEasingCurve(QEasingCurve::OutBounce);

animation.start();

Here, the animation follows a curve that bounces like a ball, just like from the start position to the end position. QEasingCurve has a large number of curves to choose from. These are defined by the QEasingCurve::Type enumeration. If you need to customize a curve, you can also implement one yourself and register it with QEasingCurve.

6, Put the animation together

Applications typically contain multiple animations. For example, you might want to move multiple drawing items simultaneously or sequentially.

Subclasses of QAnimationGroup are containers for other animations:

  • QParallelAnimationGroup (parallel group)
  • QSequentialAnimationGroup (serial group)

QParallelAnimationGroup example:

QPushButton *bonnie = new QPushButton("Bonnie");
bonnie->show();
QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry");

QPushButton *clyde = new QPushButton("Clyde");
clyde->show();
QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry");

QParallelAnimationGroup *group = new QParallelAnimationGroup;
group->addAnimation(anim1);
group->addAnimation(anim2);

group->start();

A parallel group plays multiple animations at the same time. Calling its start() function starts all the animations it manages.  

QSequentialAnimationGroup example:

QPushButton button("Animated Button");
button.show();

QPropertyAnimation anim1(&button, "geometry");
anim1.setDuration(3000);
anim1.setStartValue(QRect(0, 0, 100, 30));
anim1.setEndValue(QRect(500, 500, 100, 30));

QPropertyAnimation anim2(&button, "geometry");
anim2.setDuration(3000);
anim2.setStartValue(QRect(500, 500, 100, 30));
anim2.setEndValue(QRect(1000, 500, 100, 30));

QSequentialAnimationGroup group;

group.addAnimation(&anim1);
group.addAnimation(&anim2);

group.start();

QSequentialAnimationGroup plays animations sequentially. It starts the next animation in the list after the previous animation is completed.

Because an animation group is itself an animation, you can add it to another group. In this way, you can build a tree structure of animation and specify the playback time of animation.

Topics: Qt