Doc: Update the animation framework overview

- Clarify how the object ownership works
- Language clean up
- Update the snippets

Task-number: QTBUG-106071
Change-Id: I7caf42a150ef82dee920df4d03db6fd988796bd4
Reviewed-by: Jan Arve Sæther <jan-arve.saether@qt.io>
(cherry picked from commit 4a338aa1804a4d812cf1b9bb20274e480e3c8e9c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Venugopal Shivashankar 2022-09-08 16:09:02 +02:00 committed by Qt Cherry-pick Bot
parent 32b7278640
commit dba46183cd
3 changed files with 234 additions and 208 deletions

View File

@ -22,6 +22,10 @@
\snippet code/src_corelib_animation_qpropertyanimation.cpp 0 \snippet code/src_corelib_animation_qpropertyanimation.cpp 0
\note You can also control an animation's lifespan by choosing a
\l{QAbstractAnimation::DeletionPolicy}{delete policy} while starting the
animation.
The property name and the QObject instance of which property The property name and the QObject instance of which property
should be animated are passed to the constructor. You can then should be animated are passed to the constructor. You can then
specify the start and end value of the property. The procedure is specify the start and end value of the property. The procedure is

View File

@ -3,10 +3,94 @@
//! [0] //! [0]
QPropertyAnimation *animation = new QPropertyAnimation(myWidget, "geometry"); #include <QApplication>
animation->setDuration(10000); #include <QPushButton>
animation->setStartValue(QRect(0, 0, 100, 30)); #include <QPropertyAnimation>
animation->setEndValue(QRect(250, 250, 100, 30)); //! [1]
class MyButtonWidget : public QWidget
{
public:
MyButtonWidget(QWidget *parent = nullptr);
};
animation->start(); 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();
}
//! [1]
//! [0] //! [0]
//! [easing-curve]
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();
}
//! [easing-curve]
//! [animation-group1]
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();
}
//! [animation-group1]
//! [animation-group2]
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();
}
//! [animation-group2]

View File

@ -22,153 +22,134 @@
\keyword Animation \keyword Animation
The animation framework aims to provide an easy way for creating animated The animation framework provides an easy way to animate your GUI elements.
and smooth GUIs. By animating Qt properties, the framework provides great It enables you to animate a Qt property value of a widget or QObject.
freedom for animating widgets and other \l{QObject}s. The framework can Most of the features offered by the framework are also available in
also be used with the Graphics View framework. Many of the concepts \l{Qt Quick}, where it's possible to define animations in a declarative way.
available in the animation framework are also available in \l{Qt Quick},
where it offers a declarative way of defining animations. Much of the
knowledge acquired about the animation framework can be applied to
\l{Qt Quick}.
In this overview, we explain the basics of its architecture. We This overview explains the framework's architecture, with examples that
also show examples of the most common techniques that the demonstrate the common techniques used for animating QObject and
framework allows for animating \l{QObject}s and graphics items. GUI elements.
\tableofcontents \tableofcontents
\section1 The Animation Architecture \section1 The Animation architecture
We will in this section take a high-level look at the animation The following diagram shows the most important classes provided by the
framework's architecture and how it is used to animate Qt framework:
properties. The following diagram shows the most important classes
in the animation framework.
\image animations-architecture.png \image animations-architecture.png
The animation framework foundation consists of the base class It includes the QAbstractAnimation class, which provides the
QAbstractAnimation, and its two subclasses QVariantAnimation and necessary foundation for animations. This class defines the
QAnimationGroup. QAbstractAnimation is the ancestor of all generic properties for all animations supported by the framework.
animations. It represents basic properties that are common for all For example, the ability to start, stop, and pause an animation. The
animations in the framework; notably, the ability to start, stop, class also receives the time change notifications.
and pause an animation. It is also receives the time change
notifications.
The animation framework further provides the QPropertyAnimation The framework further provides the QVariantAnimation and
class, which inherits QVariantAnimation and performs animation of QAnimationGroup classes, which build on their base case, QAbstractAnimation.
a Qt property, which is part of Qt's \l{Meta-Object Next in the hierarchy is QPropertyAnimation, which is derived from
System}{meta-object system}. The class performs an interpolation QVariantAnmiation, and it lets you animate a Qt property of a widget or
over the property using an easing curve. So when you want to QObject. The class performs interpolation on the property value using an
animate a value, you can declare it as a property and make your easing curve. With these in place, you just need a QObject class with a
class a QObject. Note that this gives us great freedom in Qt property value that you can animate.
animating already existing widgets and other \l{QObject}s.
\note It is required that the target object you are animating is a QObject
or its subclass. This is necessary as the animation framework depends on the
\l{Meta-Object System}{meta-object system} for all the information about the
object it is animating.
Complex animations can be constructed by building a tree structure Complex animations can be constructed by building a tree structure
of \l{QAbstractAnimation}s. The tree is built by using of \l{QAbstractAnimation}s, where the tree is a QAnimationGroup that
\l{QAnimationGroup}s, which function as containers for other contains other animations. These animation groups can also contain
animations. Note also that the groups are subclasses of subgroups representing different groups or animations, such as
QAbstractAnimation, so groups can themselves contain other groups. QParallelAnimationGroup and QSequentialAnimationGroup.
Behind the scenes, the animations are controlled by a global Behind the scenes, all animations are controlled by a global
timer, which sends \l{QAbstractAnimation::updateCurrentTime()}{updates} to timer, which sends \l{QAbstractAnimation::updateCurrentTime()}{updates} about
all animations that are playing. all animations that are running.
For detailed descriptions of the classes' function and roles in For detailed information of these individual classes' and their roles in
the framework, please look up their class descriptions. the framework, refer to their documentation.
\section1 Classes in the Animation Framework \section1 Classes offered by the framework
These classes provide a framework for creating both simple and complex These classes provide the necessary infrastructure to create both simple and
animations. complex animations.
\annotatedlist animation \annotatedlist animation
\section1 Animating Qt Properties \section1 Animating Qt properties
As mentioned in the previous section, the QPropertyAnimation class can As the QPropertyAnimation class can interpolate on Qt properties, it is
interpolate over Qt properties. It is often this class that should be used used often. In fact, its superclass---QVariantAnimation---provides an
for animation of values; in fact, its superclass, QVariantAnimation, has an abstract implementation of \l{QVariantAnimation::}{updateCurrentValue()},
empty implementation of \l{QVariantAnimation::}{updateCurrentValue()}, and which does not change any value unless you change it on the
does not change any value unless we change it ourselves on the
\l{QVariantAnimation::valueChanged()}{valueChanged signal}. \l{QVariantAnimation::valueChanged()}{valueChanged signal}.
A major reason we chose to animate Qt properties is that it The framework lets you animate the Qt properties of the existing
presents us with freedom to animate already existing classes in classes in Qt. For example, the QWidget class---can be embedded in
the Qt API. Notably, the QWidget class (which we can also embed in a QGraphicsView---has properties for its bounds, colors, and so on.
a QGraphicsView) has properties for its bounds, colors, etc. The following example demonstrates how you can animate a QPushButton
Let's look at a small example: widget:
\snippet code/src_corelib_animation_qpropertyanimation.cpp 0
The example animates the \c pos Qt property of a QPushButton, to move
it from the top--left corner of the screen to the end position (250, 250),
in 10 seconds (10000 milliseconds).
It uses the linear interpolation method to control the speed of
animation between the start and end values. Try adding another value
in--between the start and end value to see how they are interpolated.
This time use the QPropertyAnimation::setKeyValueAt function to add
these values:
\code \code
QPushButton button("Animated Button"); ...
button.show(); anim->setDuration(10000);
anim->setKeyValueAt(0, QPoint(0, 0));
QPropertyAnimation animation(&button, "geometry"); anim->setKeyValueAt(0.8, QPoint(250, 250));
animation.setDuration(10000); anim->setKeyValueAt(1, QPoint(0, 0));
animation.setStartValue(QRect(0, 0, 100, 30)); ...
animation.setEndValue(QRect(250, 250, 100, 30));
animation.start();
\endcode \endcode
This code will move \c button from the top left corner of the In this example, the animation moves the button to
screen to the position (250, 250) in 10 seconds (10000 milliseconds). (250, 250) in 8 seconds, and moves it back to its original position in
the remaining 2 seconds. The button's movement is linear-interpolated
between these points.
The example above will do a linear interpolation between the You can also animate a QObject's value that is not declared as a Qt
start and end value. It is also possible to set values property, if the value has a setter method. In such cases, derive
situated between the start and end value. The interpolation a new class from the class that contains the value, and add a Qt property
will then go by these points. for that value with the setter.
\code \note Each Qt property requires a getter also, so you should provide a
QPushButton button("Animated Button"); getter if that is not defined.
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();
\endcode
In this example, 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 movement will be linearly
interpolated between these points.
You also have the possibility to animate values of a QObject
that is not declared as a Qt property. The only requirement is
that this value has a setter. You can then subclass the class
containing the value and declare a property that uses this setter.
Note that each Qt property requires a getter, so you will need to
provide a getter yourself if this is not defined.
\code \code
class MyGraphicsRectItem : public QObject, public QGraphicsRectItem class MyGraphicsRectItem : public QObject, public QGraphicsRectItem
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry) Q_PROPERTY(QPointF pos READ pos WRITE setPos)
}; };
\endcode \endcode
In the above code example, we subclass QGraphicsRectItem and In this example, the \c MyGraphicsRectItem derives from
define a geometry property. We can now animate the widgets QGraphicsRectItem and QObject, and defines the \c pos property. You can
geometry even if QGraphicsRectItem does not provide the geometry animate the item's \c pos even if QGraphicsRectItem does not provide
property. the \c pos property.
For a general introduction to the Qt property system, see its For a general introduction to the Qt property system, refer to
\l{Qt's Property System}{overview}. \l{Qt's Property System}.
\section1 Animations and the Graphics View Framework \section1 Animations and the Graphics View Framework
When you want to animate \l{QGraphicsItem}s, you also use QPropertyAnimation can also be used to animate a QGraphicsItem, which does
QPropertyAnimation. However, QGraphicsItem does not inherit QObject. not inherit QObject. In such cases, you derive a class from the graphics
A good solution is to subclass the graphics item you wish to animate. item that you want to animate. This derived class should also inherit form
This class will then also inherit QObject. QObject to enable using QPropertyAnimation on a QGraphicsItem. The
This way, QPropertyAnimation can be used for \l{QGraphicsItem}s. following example shows how this is done:
The example below shows how this is done. Another possibility is
to inherit QGraphicsWidget, which already is a QObject.
\code \code
class Pixmap : public QObject, public QGraphicsPixmapItem class Pixmap : public QObject, public QGraphicsPixmapItem
@ -176,121 +157,78 @@
Q_OBJECT Q_OBJECT
Q_PROPERTY(QPointF pos READ pos WRITE setPos) Q_PROPERTY(QPointF pos READ pos WRITE setPos)
... ...
}
\endcode \endcode
As described in the previous section, we need to define \note You can also derive from QGraphicsWidget, which already is a
properties that we wish to animate. QObject.
Note that QObject must be the first class inherited as the As described in the previous section, you need to define
meta-object system demands this. properties that you want to animate. The derived class must inherit
from QObject first as the meta-object system requires it.
\section1 Easing Curves \section1 Easing curves
As mentioned, QPropertyAnimation performs an interpolation between A QPropertyAnimation performs linear interpolation
the start and end property value. In addition to adding more key between the start and end property values. In addition to adding more key
values to the animation, you can also use an easing curve. Easing values to the animation, you can also choose an easing curve to control the
curves describe a function that controls how the speed of the speed of interpolation between 0 and 1, without changing the
interpolation between 0 and 1 should be, and are useful if you path.
want to control the speed of an animation without changing the
path of the interpolation.
\code
QPushButton button("Animated Button");
button.show();
QPropertyAnimation animation(&button, "geometry"); \snippet code/src_corelib_animation_qpropertyanimation.cpp easing-curve
animation.setDuration(3000);
animation.setStartValue(QRect(0, 0, 100, 30));
animation.setEndValue(QRect(250, 250, 100, 30));
animation.setEasingCurve(QEasingCurve::OutBounce); In this example, the animation follows a curve that makes the
\c button bounce like a ball. QEasingCurve offers a large collection of curves
animation.start(); to choose from the QEasingCurve::Type enum. If you want
\endcode to use another curve that is not available, implement one yourself and
Here the animation will follow a curve that makes it bounce like a
ball as if it was dropped from the start to the end position.
QEasingCurve has a large collection of curves for you to choose
from. These are defined by the QEasingCurve::Type enum. If you are
in need of another curve, you can also implement one yourself, and
register it with QEasingCurve. register it with QEasingCurve.
\omit Drop this for the first Lab release \section1 Grouping animations
(Example of custom easing curve (without the actual impl of
the function I expect)
\endomit
\section1 Putting Animations Together An application often contains more than one animation. For
example, it wants to move more than one graphics item
An application will often contain more than one animation. For
instance, you might want to move more than one graphics item
simultaneously or move them in sequence after each other. simultaneously or move them in sequence after each other.
The subclasses of QAnimationGroup (QSequentialAnimationGroup and The subclasses of QAnimationGroup---QSequentialAnimationGroup and
QParallelAnimationGroup) are containers for other animations so QParallelAnimationGroup---are containers for other animations so
that these animations can be animated either in sequence or that these animations can be animated either in sequence or
parallel. The QAnimationGroup is an example of an animation that parallel. The QAnimationGroup does not animate properties, but it
does not animate properties, but it gets notified of time changes gets notified of time changes periodically. This enables it to
periodically. This enables it to forward those time changes to its forward those time changes to the animation groups, which control when
contained animations, and thereby controlling when its animations their animations are played.
are played.
Let's look at code examples that use both The two following examples demonstrate the use of both
QSequentialAnimationGroup and QParallelAnimationGroup, starting QSequentialAnimationGroup and QParallelAnimationGroup:
off with the latter.
\code \snippet code/src_corelib_animation_qpropertyanimation.cpp animation-group1
QPushButton *bonnie = new QPushButton("Bonnie");
bonnie->show();
QPushButton *clyde = new QPushButton("Clyde");
clyde->show();
QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry");
// Set up anim1
QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry");
// Set up anim2
QParallelAnimationGroup *group = new QParallelAnimationGroup;
group->addAnimation(anim1);
group->addAnimation(anim2);
group->start();
\endcode
A parallel group plays more than one animation at the same time. A parallel group plays more than one animation at the same time.
Calling its \l{QAbstractAnimation::}{start()} function will start Its \l{QAbstractAnimation::}{start()} function starts all
all animations it governs. animations that are part of the group.
\code \snippet code/src_corelib_animation_qpropertyanimation.cpp animation-group2
QPushButton button("Animated Button");
button.show();
QPropertyAnimation anim1(&button, "geometry"); As the name suggests, a QSequentialAnimationGroup plays
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();
\endcode
As you no doubt have guessed, QSequentialAnimationGroup plays
its animations in sequence. It starts the next animation in its animations in sequence. It starts the next animation in
the list after the previous is finished. the list after the previous finishes.
Since an animation group is an animation itself, you can add A group is an animation itself, so you can add
it to another group. This way, you can build a tree structure it to another group. This way, building an animation tree, which define
of animations which specifies when the animations are played when the animations are played in relation to each other.
in relation to each other.
\section1 Object ownership
A QPropertyAnimation should always have a parent that controls
its lifespan. A typical application may include several animations that
are grouped, where the animation group takes ownership of those animations.
An independent QProperyAnimation must be explicitly assigned a parent to
control its lifespan. In the following example, you can see that an
independent QPropertyAnimation has the QApplication instance as its
parent:
\snippet code/src_corelib_animation_qpropertyanimation.cpp 0
\note You can also control the animation's lifespan by choosing a
\l{QAbstractAnimation::DeletionPolicy}{delete policy} while starting it.
*/ */