|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the documentation of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 /*! |
|
43 \group animation |
|
44 \title Animation Framework |
|
45 */ |
|
46 |
|
47 /*! |
|
48 \page animation-overview.html |
|
49 \title The Animation Framework |
|
50 |
|
51 \brief An overview of the Animation Framework |
|
52 |
|
53 \ingroup frameworks-technologies |
|
54 |
|
55 \keyword Animation |
|
56 |
|
57 The animation framework is part of the Kinetic project, and aims |
|
58 to provide an easy way for creating animated and smooth GUI's. By |
|
59 animating Qt properties, the framework provides great freedom for |
|
60 animating widgets and other \l{QObject}s. The framework can also |
|
61 be used with the Graphics View framework. |
|
62 |
|
63 In this overview, we explain the basics of its architecture. We |
|
64 also show examples of the most common techniques that the |
|
65 framework allows for animating QObjects and graphics items. |
|
66 |
|
67 \tableofcontents |
|
68 |
|
69 \section1 The Animation Architecture |
|
70 |
|
71 We will in this section take a high-level look at the animation |
|
72 framework's architecture and how it is used to animate Qt |
|
73 properties. The following diagram shows the most important classes |
|
74 in the animation framework. |
|
75 |
|
76 \image animations-architecture.png |
|
77 |
|
78 The animation framework foundation consists of the base class |
|
79 QAbstractAnimation, and its two subclasses QVariantAnimation and |
|
80 QAnimationGroup. QAbstractAnimation is the ancestor of all |
|
81 animations. It represents basic properties that are common for all |
|
82 animations in the framework; notably, the ability to start, stop, |
|
83 and pause an animation. It is also receives the time change |
|
84 notifications. |
|
85 |
|
86 The animation framework further provides the QPropertyAnimation |
|
87 class, which inherits QVariantAnimation and performs animation of |
|
88 a Qt property, which is part of Qt's \l{Meta-Object |
|
89 System}{meta-object system}. The class performs an interpolation |
|
90 over the property using an easing curve. So when you want to |
|
91 animate a value, you can declare it as a property and make your |
|
92 class a QObject. Note that this gives us great freedom in |
|
93 animating already existing widgets and other \l{QObject}s. |
|
94 |
|
95 Complex animations can be constructed by building a tree structure |
|
96 of \l{QAbstractAnimation}s. The tree is built by using |
|
97 \l{QAnimationGroup}s, which function as containers for other |
|
98 animations. Note also that the groups are subclasses of |
|
99 QAbstractAnimation, so groups can themselves contain other groups. |
|
100 |
|
101 The animation framework can be used on its own, but is also |
|
102 designed to be part of the state machine framework (See the |
|
103 \l{The State Machine Framework}{state machine framework} for an |
|
104 introduction to the Qt state machine). The state machine provides |
|
105 a special state that can play an animation. A QState can also set |
|
106 properties when the state is entered or exited, and this special |
|
107 animation state will interpolate between these values when given a |
|
108 QPropertyAnimation. We will look more closely at this later. |
|
109 |
|
110 Behind the scenes, the animations are controlled by a global |
|
111 timer, which sends \l{QAbstractAnimation::updateCurrentTime()}{updates} to |
|
112 all animations that are playing. |
|
113 |
|
114 For detailed descriptions of the classes' function and roles in |
|
115 the framework, please look up their class descriptions. |
|
116 |
|
117 \section1 Classes in the Animation Framework |
|
118 |
|
119 These classes provide a framework for creating both simple and complex |
|
120 animations. |
|
121 |
|
122 \annotatedlist animation |
|
123 |
|
124 \section1 Animating Qt Properties |
|
125 |
|
126 As mentioned in the previous section, the QPropertyAnimation class |
|
127 can interpolate over Qt properties. It is this class that should |
|
128 be used for animation of values; in fact, its superclass, |
|
129 QVariantAnimation, is an abstract class, and cannot be used |
|
130 directly. |
|
131 |
|
132 A major reason we chose to animate Qt properties is that it |
|
133 presents us with freedom to animate already existing classes in |
|
134 the Qt API. Notably, the QWidget class (which we can also embed in |
|
135 a QGraphicsView) has properties for its bounds, colors, etc. |
|
136 Let's look at a small example: |
|
137 |
|
138 \code |
|
139 QPushButton button("Animated Button"); |
|
140 button.show(); |
|
141 |
|
142 QPropertyAnimation animation(&button, "geometry"); |
|
143 animation.setDuration(10000); |
|
144 animation.setStartValue(QRect(0, 0, 100, 30)); |
|
145 animation.setEndValue(QRect(250, 250, 100, 30)); |
|
146 |
|
147 animation.start(); |
|
148 \endcode |
|
149 |
|
150 This code will move \c button from the top left corner of the |
|
151 screen to the position (250, 250) in 10 seconds (10000 milliseconds). |
|
152 |
|
153 The example above will do a linear interpolation between the |
|
154 start and end value. It is also possible to set values |
|
155 situated between the start and end value. The interpolation |
|
156 will then go by these points. |
|
157 |
|
158 \code |
|
159 QPushButton button("Animated Button"); |
|
160 button.show(); |
|
161 |
|
162 QPropertyAnimation animation(&button, "geometry"); |
|
163 animation.setDuration(10000); |
|
164 |
|
165 animation.setKeyValueAt(0, QRect(0, 0, 100, 30)); |
|
166 animation.setKeyValueAt(0.8, QRect(250, 250, 100, 30)); |
|
167 animation.setKeyValueAt(1, QRect(0, 0, 100, 30)); |
|
168 |
|
169 animation.start(); |
|
170 \endcode |
|
171 |
|
172 In this example, the animation will take the button to (250, 250) |
|
173 in 8 seconds, and then move it back to its original position in |
|
174 the remaining 2 seconds. The movement will be linearly |
|
175 interpolated between these points. |
|
176 |
|
177 You also have the possibility to animate values of a QObject |
|
178 that is not declared as a Qt property. The only requirement is |
|
179 that this value has a setter. You can then subclass the class |
|
180 containing the value and declare a property that uses this setter. |
|
181 Note that each Qt property requires a getter, so you will need to |
|
182 provide a getter yourself if this is not defined. |
|
183 |
|
184 \code |
|
185 class MyGraphicsRectItem : public QObject, public QGraphicsRectItem |
|
186 { |
|
187 Q_OBJECT |
|
188 Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry) |
|
189 }; |
|
190 \endcode |
|
191 |
|
192 In the above code example, we subclass QGraphicsRectItem and |
|
193 define a geometry property. We can now animate the widgets |
|
194 geometry even if QGraphicsRectItem does not provide the geometry |
|
195 property. |
|
196 |
|
197 For a general introduction to the Qt property system, see its |
|
198 \l{Qt's Property System}{overview}. |
|
199 |
|
200 \section1 Animations and the Graphics View Framework |
|
201 |
|
202 When you want to animate \l{QGraphicsItem}s, you also use |
|
203 QPropertyAnimation. However, QGraphicsItem does not inherit QObject. |
|
204 A good solution is to subclass the graphics item you wish to animate. |
|
205 This class will then also inherit QObject. |
|
206 This way, QPropertyAnimation can be used for \l{QGraphicsItem}s. |
|
207 The example below shows how this is done. Another possibility is |
|
208 to inherit QGraphicsWidget, which already is a QObject. |
|
209 |
|
210 \code |
|
211 class Pixmap : public QObject, public QGraphicsPixmapItem |
|
212 { |
|
213 Q_OBJECT |
|
214 Q_PROPERTY(QPointF pos READ pos WRITE setPos) |
|
215 ... |
|
216 \endcode |
|
217 |
|
218 As described in the previous section, we need to define |
|
219 properties that we wish to animate. |
|
220 |
|
221 Note that QObject must be the first class inherited as the |
|
222 meta-object system demands this. |
|
223 |
|
224 \section1 Easing Curves |
|
225 |
|
226 As mentioned, QPropertyAnimation performs an interpolation between |
|
227 the start and end property value. In addition to adding more key |
|
228 values to the animation, you can also use an easing curve. Easing |
|
229 curves describe a function that controls how the speed of the |
|
230 interpolation between 0 and 1 should be, and are useful if you |
|
231 want to control the speed of an animation without changing the |
|
232 path of the interpolation. |
|
233 |
|
234 \code |
|
235 QPushButton button("Animated Button"); |
|
236 button.show(); |
|
237 |
|
238 QPropertyAnimation animation(&button, "geometry"); |
|
239 animation.setDuration(3000); |
|
240 animation.setStartValue(QRect(0, 0, 100, 30)); |
|
241 animation.setEndValue(QRect(250, 250, 100, 30)); |
|
242 |
|
243 animation.setEasingCurve(QEasingCurve::OutBounce); |
|
244 |
|
245 animation.start(); |
|
246 \endcode |
|
247 |
|
248 Here the animation will follow a curve that makes it bounce like a |
|
249 ball as if it was dropped from the start to the end position. |
|
250 QEasingCurve has a large collection of curves for you to choose |
|
251 from. These are defined by the QEasingCurve::Type enum. If you are |
|
252 in need of another curve, you can also implement one yourself, and |
|
253 register it with QEasingCurve. |
|
254 |
|
255 \omit Drop this for the first Lab release |
|
256 (Example of custom easing curve (without the actual impl of |
|
257 the function I expect) |
|
258 \endomit |
|
259 |
|
260 \section1 Putting Animations Together |
|
261 |
|
262 An application will often contain more than one animation. For |
|
263 instance, you might want to move more than one graphics item |
|
264 simultaneously or move them in sequence after each other. |
|
265 |
|
266 The subclasses of QAnimationGroup (QSequentialAnimationGroup and |
|
267 QParallelAnimationGroup) are containers for other animations so |
|
268 that these animations can be animated either in sequence or |
|
269 parallel. The QAnimationGroup is an example of an animation that |
|
270 does not animate properties, but it gets notified of time changes |
|
271 periodically. This enables it to forward those time changes to its |
|
272 contained animations, and thereby controlling when its animations |
|
273 are played. |
|
274 |
|
275 Let's look at code examples that use both |
|
276 QSequentialAnimationGroup and QParallelAnimationGroup, starting |
|
277 off with the latter. |
|
278 |
|
279 \code |
|
280 QPushButton *bonnie = new QPushButton("Bonnie"); |
|
281 bonnie->show(); |
|
282 |
|
283 QPushButton *clyde = new QPushButton("Clyde"); |
|
284 clyde->show(); |
|
285 |
|
286 QPropertyAnimation *anim1 = new QPropertyAnimation(bonnie, "geometry"); |
|
287 // Set up anim1 |
|
288 |
|
289 QPropertyAnimation *anim2 = new QPropertyAnimation(clyde, "geometry"); |
|
290 // Set up anim2 |
|
291 |
|
292 QParallelAnimationGroup *group = new QParallelAnimationGroup; |
|
293 group->addAnimation(anim1); |
|
294 group->addAnimation(anim2); |
|
295 |
|
296 group->start(); |
|
297 \endcode |
|
298 |
|
299 A parallel group plays more than one animation at the same time. |
|
300 Calling its \l{QAbstractAnimation::}{start()} function will start |
|
301 all animations it governs. |
|
302 |
|
303 \code |
|
304 QPushButton button("Animated Button"); |
|
305 button.show(); |
|
306 |
|
307 QPropertyAnimation anim1(&button, "geometry"); |
|
308 anim1.setDuration(3000); |
|
309 anim1.setStartValue(QRect(0, 0, 100, 30)); |
|
310 anim1.setEndValue(QRect(500, 500, 100, 30)); |
|
311 |
|
312 QPropertyAnimation anim2(&button, "geometry"); |
|
313 anim2.setDuration(3000); |
|
314 anim2.setStartValue(QRect(500, 500, 100, 30)); |
|
315 anim2.setEndValue(QRect(1000, 500, 100, 30)); |
|
316 |
|
317 QSequentialAnimationGroup group; |
|
318 |
|
319 group.addAnimation(&anim1); |
|
320 group.addAnimation(&anim2); |
|
321 |
|
322 group.start(); |
|
323 \endcode |
|
324 |
|
325 As you no doubt have guessed, QSequentialAnimationGroup plays |
|
326 its animations in sequence. It starts the next animation in |
|
327 the list after the previous is finished. |
|
328 |
|
329 Since an animation group is an animation itself, you can add |
|
330 it to another group. This way, you can build a tree structure |
|
331 of animations which specifies when the animations are played |
|
332 in relation to each other. |
|
333 |
|
334 \section1 Animations and States |
|
335 |
|
336 When using a \l{The State Machine Framework}{state machine}, we |
|
337 can associate one or more animations to a transition between states |
|
338 using a QSignalTransition or QEventTransition class. These classes |
|
339 are both derived from QAbstractTransition, which defines the |
|
340 convenience function \l{QAbstractTransition::}{addAnimation()} that |
|
341 enables the appending of one or more animations triggered when the |
|
342 transition occurs. |
|
343 |
|
344 We also have the possibility to associate properties with the |
|
345 states rather than setting the start and end values ourselves. |
|
346 Below is a complete code example that animates the geometry of a |
|
347 QPushButton. |
|
348 |
|
349 \code |
|
350 QPushButton *button = new QPushButton("Animated Button"); |
|
351 button->show(); |
|
352 |
|
353 QStateMachine *machine = new QStateMachine; |
|
354 |
|
355 QState *state1 = new QState(machine->rootState()); |
|
356 state1->assignProperty(button, "geometry", QRect(0, 0, 100, 30)); |
|
357 machine->setInitialState(state1); |
|
358 |
|
359 QState *state2 = new QState(machine->rootState()); |
|
360 state2->assignProperty(button, "geometry", QRect(250, 250, 100, 30)); |
|
361 |
|
362 QSignalTransition *transition1 = state1->addTransition(button, |
|
363 SIGNAL(clicked()), state2); |
|
364 transition1->addAnimation(new QPropertyAnimation(button, "geometry")); |
|
365 |
|
366 QSignalTransition *transition2 = state2->addTransition(button, |
|
367 SIGNAL(clicked()), state1); |
|
368 transition2->addAnimation(new QPropertyAnimation(button, "geometry")); |
|
369 |
|
370 machine->start(); |
|
371 \endcode |
|
372 |
|
373 For a more comprehensive example of how to use the state machine |
|
374 framework for animations, see the states example (it lives in the |
|
375 \c{examples/animation/states} directory). |
|
376 */ |
|
377 |