1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtCore module of the Qt Toolkit.
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
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
43 \class QPropertyAnimation
44 \brief The QPropertyAnimation class animates Qt properties
49 QPropertyAnimation interpolates over \l{Qt's Property System}{Qt
50 properties}. As property values are stored in \l{QVariant}s, the
51 class inherits QVariantAnimation, and supports animation of the
52 same \l{QVariant::Type}{variant types} as its super class.
54 A class declaring properties must be a QObject. To make it
55 possible to animate a property, it must provide a setter (so that
56 QPropertyAnimation can set the property's value). Note that this
57 makes it possible to animate many of Qt's widgets. Let's look at
61 QPropertyAnimation *animation = new QPropertyAnimation(myWidget, "geometry");
62 animation->setDuration(10000);
63 animation->setStartValue(QRect(0, 0, 100, 30));
64 animation->setEndValue(QRect(250, 250, 100, 30));
69 The property name and the QObject instance of which property
70 should be animated are passed to the constructor. You can then
71 specify the start and end value of the property. The procedure is
72 equal for properties in classes you have implemented
73 yourself--just check with QVariantAnimation that your QVariant
76 The QVariantAnimation class description explains how to set up the
77 animation in detail. Note, however, that if a start value is not
78 set, the property will start at the value it had when the
79 QPropertyAnimation instance was created.
81 QPropertyAnimation works like a charm on its own. For complex
82 animations that, for instance, contain several objects,
83 QAnimationGroup is provided. An animation group is an animation
84 that can contain other animations, and that can manage when its
85 animations are played. Look at QParallelAnimationGroup for an
88 \sa QVariantAnimation, QAnimationGroup, {The Animation Framework}
91 #include "qpropertyanimation.h"
92 #include "qanimationgroup.h"
93 #include "qpropertyanimation_p.h"
95 #include <private/qmutexpool_p.h>
97 #ifndef QT_NO_ANIMATION
101 void QPropertyAnimationPrivate::updateMetaProperty()
103 if (!target
|| propertyName
.isEmpty()) {
104 propertyType
= QVariant::Invalid
;
109 //propertyType will be set to a valid type only if there is a Q_PROPERTY
110 //otherwise it will be set to QVariant::Invalid at the end of this function
111 propertyType
= targetValue
->property(propertyName
).userType();
112 propertyIndex
= targetValue
->metaObject()->indexOfProperty(propertyName
);
114 if (propertyType
!= QVariant::Invalid
)
115 convertValues(propertyType
);
116 if (propertyIndex
== -1) {
117 //there is no Q_PROPERTY on the object
118 propertyType
= QVariant::Invalid
;
119 if (!targetValue
->dynamicPropertyNames().contains(propertyName
))
120 qWarning("QPropertyAnimation: you're trying to animate a non-existing property %s of your QObject", propertyName
.constData());
121 } else if (!targetValue
->metaObject()->property(propertyIndex
).isWritable()) {
122 qWarning("QPropertyAnimation: you're trying to animate the non-writable property %s of your QObject", propertyName
.constData());
126 void QPropertyAnimationPrivate::updateProperty(const QVariant
&newValue
)
128 if (state
== QAbstractAnimation::Stopped
)
132 q_func()->stop(); //the target was destroyed we need to stop the animation
136 if (newValue
.userType() == propertyType
) {
137 //no conversion is needed, we directly call the QMetaObject::metacall
138 void *data
= const_cast<void*>(newValue
.constData());
139 QMetaObject::metacall(targetValue
, QMetaObject::WriteProperty
, propertyIndex
, &data
);
141 targetValue
->setProperty(propertyName
.constData(), newValue
);
146 Construct a QPropertyAnimation object. \a parent is passed to QObject's
149 QPropertyAnimation::QPropertyAnimation(QObject
*parent
)
150 : QVariantAnimation(*new QPropertyAnimationPrivate
, parent
)
155 Construct a QPropertyAnimation object. \a parent is passed to QObject's
156 constructor. The animation changes the property \a propertyName on \a
157 target. The default duration is 250ms.
159 \sa targetObject, propertyName
161 QPropertyAnimation::QPropertyAnimation(QObject
*target
, const QByteArray
&propertyName
, QObject
*parent
)
162 : QVariantAnimation(*new QPropertyAnimationPrivate
, parent
)
164 setTargetObject(target
);
165 setPropertyName(propertyName
);
169 Destroys the QPropertyAnimation instance.
171 QPropertyAnimation::~QPropertyAnimation()
177 \property QPropertyAnimation::targetObject
178 \brief the target QObject for this animation.
180 This property defines the target QObject for this animation.
182 QObject
*QPropertyAnimation::targetObject() const
184 return d_func()->target
.data();
187 void QPropertyAnimation::setTargetObject(QObject
*target
)
189 Q_D(QPropertyAnimation
);
190 if (d
->targetValue
== target
)
193 if (d
->state
!= QAbstractAnimation::Stopped
) {
194 qWarning("QPropertyAnimation::setTargetObject: you can't change the target of a running animation");
198 d
->target
= d
->targetValue
= target
;
199 d
->updateMetaProperty();
203 \property QPropertyAnimation::propertyName
204 \brief the target property name for this animation
206 This property defines the target property name for this animation. The
207 property name is required for the animation to operate.
209 QByteArray
QPropertyAnimation::propertyName() const
211 Q_D(const QPropertyAnimation
);
212 return d
->propertyName
;
215 void QPropertyAnimation::setPropertyName(const QByteArray
&propertyName
)
217 Q_D(QPropertyAnimation
);
218 if (d
->state
!= QAbstractAnimation::Stopped
) {
219 qWarning("QPropertyAnimation::setPropertyName: you can't change the property name of a running animation");
223 d
->propertyName
= propertyName
;
224 d
->updateMetaProperty();
231 bool QPropertyAnimation::event(QEvent
*event
)
233 return QVariantAnimation::event(event
);
237 This virtual function is called by QVariantAnimation whenever the current value
238 changes. \a value is the new, updated value. It updates the current value
239 of the property on the target object.
241 \sa currentValue, currentTime
243 void QPropertyAnimation::updateCurrentValue(const QVariant
&value
)
245 Q_D(QPropertyAnimation
);
246 d
->updateProperty(value
);
252 If the startValue is not defined when the state of the animation changes from Stopped to Running,
253 the current property value is used as the initial value for the animation.
255 void QPropertyAnimation::updateState(QAbstractAnimation::State newState
,
256 QAbstractAnimation::State oldState
)
258 Q_D(QPropertyAnimation
);
260 if (!d
->target
&& oldState
== Stopped
) {
261 qWarning("QPropertyAnimation::updateState (%s): Changing state of an animation without target",
262 d
->propertyName
.constData());
266 QVariantAnimation::updateState(newState
, oldState
);
268 QPropertyAnimation
*animToStop
= 0;
271 QMutexLocker
locker(QMutexPool::globalInstanceGet(&staticMetaObject
));
273 typedef QPair
<QObject
*, QByteArray
> QPropertyAnimationPair
;
274 typedef QHash
<QPropertyAnimationPair
, QPropertyAnimation
*> QPropertyAnimationHash
;
275 static QPropertyAnimationHash hash
;
276 //here we need to use value because we need to know to which pointer
277 //the animation was referring in case stopped because the target was destroyed
278 QPropertyAnimationPair
key(d
->targetValue
, d
->propertyName
);
279 if (newState
== Running
) {
280 d
->updateMetaProperty();
281 animToStop
= hash
.value(key
, 0);
282 hash
.insert(key
, this);
283 // update the default start value
284 if (oldState
== Stopped
) {
285 d
->setDefaultStartEndValue(d
->targetValue
->property(d
->propertyName
.constData()));
286 //let's check if we have a start value and an end value
287 if (!startValue().isValid() && (d
->direction
== Backward
|| !d
->defaultStartEndValue
.isValid())) {
288 qWarning("QPropertyAnimation::updateState (%s, %s, %s): starting an animation without start value",
289 d
->propertyName
.constData(), d
->target
.data()->metaObject()->className(),
290 qPrintable(d
->target
.data()->objectName()));
292 if (!endValue().isValid() && (d
->direction
== Forward
|| !d
->defaultStartEndValue
.isValid())) {
293 qWarning("QPropertyAnimation::updateState (%s, %s, %s): starting an animation without end value",
294 d
->propertyName
.constData(), d
->target
.data()->metaObject()->className(),
295 qPrintable(d
->target
.data()->objectName()));
298 } else if (hash
.value(key
) == this) {
303 //we need to do that after the mutex was unlocked
305 // try to stop the top level group
306 QAbstractAnimation
*current
= animToStop
;
307 while (current
->group() && current
->state() != Stopped
)
308 current
= current
->group();
313 #include "moc_qpropertyanimation.cpp"
317 #endif //QT_NO_ANIMATION