===== Le framework animation ===== Le framework animation fait partie du projet Kinetic, et vise à fournir un moyen facile pour la création d'interfaces graphiques animées et lisses. En animant les propriétés Qt, le framework fournit une grande liberté d'animation de widgets et de [[QObject]]. Le framework peut également être utilisé avec le framework Graphics View. Dans cet aperçu, nous expliquons les bases de son architecture. Nous montrons également des exemples des techniques les plus courantes que le framework permet pour animer les [[QObject]] et les éléments graphiques. * [[#L'architecture du framework animation]] * [[#Les classes contenues dans le framework animation]] * [[#Animer les propriétés Qt]] * [[#Les animations et le framework Graphics View]] * [[#Assouplissement des courbes]] * [[#Jouer des animations simultanément]] * [[#Machine à état et animations]] ==== L'architecture du framework animation ==== Nous allons dans cette section regarder le haut de l'architecture du framework animation et voir comment il est utilisé pour animer les propriétés Qt. Le diagramme suivant montre les classes les plus importantes du framework animation. {{ http://qt.developpez.com/doc/4.6/images/animations-architecture.png |}} Les fondations du framework animation se composent de la classe de base [[QAbstractAnimation]] et de ses deux sous-classes, [[QVariantAnimation]] et [[QAnimationGroup]]. [[QAbstractAnimation]] est l'ancêtre de toutes les animations. Il représente les propriétés de base communes à toutes les animations du framework, notamment la capacité de démarrer, arrêter et mettre en pause une animation. Il reçoit également les notifications de changement du temps. La framework animation prévoit en plus la classe [[QPropertyAnimation]], qui hérite de [[QVariantAnimation]] et réalise l'animation d'une propriété Qt, qui fait partie du [[metaobjects|systéme meta-objet]] de Qt. La classe effectue une interpolation sur la propriété en utilisant un assouplissement de la courbe. Donc, quand vous voulez animer une valeur, vous pouvez la déclarer comme une propriété et faire de votre classe un [[QObject]]. Notez que cela nous donne une grande liberté dans l'animation de widgets déjà existants et d'autres [[QObject]]. Des animations complexes peuvent être construites en créant une structure en arbre de [[QAbstractAnimation]]. L'arbre est créé en utilisant des [[QAnimationGroup]], qui fonctionnent comme des conteneurs pour d'autres animations. Notez également que les groupes sont des sous-classes de [[QAbstractAnimation]], ces groupes peuvent donc eux-mêmes contenir d'autres groupes. Le framework animation peut être utilisé seul, mais est également conçu pour faire partie du framework machine à état (voir [[statemachine-api|le framework machine à état]] pour une introduction à la machine à état de Qt). La machine à état fournit un état spécial qui peut jouer une animation. Un [[QState]] peut également définir des propriétés quand l'état est //entered// ou //exited//, et cet état spécial d'animation sera interpolé entre ces valeurs lorsqu'on lui donne une [[QPropertyAnimation]]. Nous allons examiner plus en détail cette partie par la suite. À l'intérieur du framework, les animations sont contrôlées par un timer global, qui envoie des mises à jour à toutes les animations qui sont jouées. Pour une description détaillée des fonctions de classes et de leur rôle dans le framework, vous pouvez regarder les descriptions des classes. ==== Les classes contenues dans le framework animation ==== Ces classes offrent un framework permettant de créer des animations à la fois simples et complexes. | [[QAbstractAnimation]] | Base de toutes les animations. | | [[QAnimationGroup]] | Classe abstraite pour les groupes d'animations. | | [[QEasingCurve]] | Assouplissement de courbe pour contrôler les animations. | | [[QParallelAnimationGroup]] | Groupe d'animations parallèles. | | [[QPauseAnimation]] | Pause pour le [[QSequentialAnimationGroup]]. | | [[QPropertyAnimation]] | Anime les propriétés Qt. | | [[QSequentialAnimationGroup]] | Groupe d'animations séquentielles. | | [[QTimeLine]] | Ligne temporelle pour contrôler les animations. | | [[QVariantAnimation]] | Classe abstraite de base pour toutes les animations. | ==== Animer les propriétés Qt ==== Comme mentionné dans la section précédente, la classe [[QPropertyAnimation]] peut interpoler des propriétés Qt. C'est cette classe qui doit être utilisée pour animer des valeurs. En fait, sa superclasse, [[QVariantAnimation]], est abstraite et ne peut pas être utilisée directement. Une des raisons majeures qui nous a poussé à choisir d'animer les propriétés Qt est que cela présente pour nous une grande liberté dans l'animation de classe existante dans l'API Qt. Notamment, la classe [[QWidget]] (que nous pouvons également intégrer dans un [[QGraphicsView]]) a des propriétés pour ses limites, ses couleurs, etc. Regardons ce petit exemple : 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(); Ce code va déplacer un bouton du coin supérieur gauche de l'écran à la position (250, 250) en 10 secondes (10000 millisecondes). L'exemple ci-dessus va réaliser une interpolation linéaire entre la valeur de début et la valeur de fin. Il est également possible de fixer des valeurs situées entre la valeur de début et la valeur de fin. L'interpolation passera ensuite par ces 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(); Dans cet exemple, l'animation emmènera ''button'' à la position (250, 250) en huit secondes, puis le déplacera à sa position initiale au cours des deux dernières secondes. Le mouvement sera interpolé linéairement entre ces points. Vous avez également la possibilité d'animer des valeurs d'un [[QObject]] qui n'est pas déclaré comme une propriété Qt. La seule exigence est que cette valeur ait un modificateur. Vous pouvez ensuite réaliser une sous-classe de la classe contenant la valeur et déclarer une propriété qui est utilisée par le modificateur. Notez que chaque propriété Qt exige un accesseur, vous devez donc fournir un accesseur vous-même s'il n'est pas défini. class MyGraphicsRectItem : public QObject, public QGraphicsRectItem { Q_OBJECT Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry) }; Dans l'exemple de code ci-dessus, nous réalisons une sous-classe de [[QGraphicsRectItem]] et définissons une propriété géométrique. Nous pouvons maintenant animer la géométrie de widgets même si [[QGraphicsRectItem]] ne prévoit pas de propriété géométrique. Pour une introduction générale au système de propriété Qt, voir sa [[properties|vue d'ensemble]]. ==== Les animations et le framework Graphics View ==== Lorsque vous souhaitez animer des [[QGraphicsItems]], vous utilisez également [[QPropertyAnimation]]. Toutefois, [[QGraphicsItem]] n'hérite pas [[QObject]]. Une bonne solution est de réaliser une sous-classe de l'élément graphique que vous souhaitez animer. Cette classe héritera ensuite également de [[QObject]]. De cette façon, QPropertyAnimation peut être utilisée pour les [[QGraphicsItems]]. L'exemple ci-dessous montre comment cela est fait. Une autre possibilité est d'hériter de [[QGraphicsWidget]], qui est déjà un [[QObject]]. class Pixmap : public QObject, public QGraphicsPixmapItem { Q_OBJECT Q_PROPERTY(QPointF pos READ pos WRITE setPos) ... Comme décrit dans la section précédente, nous devons définir les propriétés que nous souhaitons animer. Notez que [[QObject]] doit être la première classe héritée, il s'agit d'une exigence du système meta-objet. ==== Assouplissement des courbes (Easing Curves) ==== Comme mentionné, [[QPropertyAnimation]] effectue une interpolation entre la valeur de la propriété du début à la fin. En plus d'ajouter plusieurs valeurs clés à l'animation, vous pouvez également utiliser un assouplissement de la courbe. L'assouplissement des courbes décrit une fonction qui contrôle la façon dont doit être définie la vitesse de l'interpolation entre 0 et 1, il est utile si vous voulez contrôler la vitesse d'une animation sans en changer la trajectoire de l'interpolation. 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(); Ici, l'animation va suivre une courbe qui la fait rebondir comme une balle comme si elle avait été lâchée de la position du début à la fin. [[QEasingCurve]] a une grande collection de courbes que vous pouvez choisir. Elles sont définies par l'énumération [[qeasingcurve#type-enum|QEasingCurve::type]]. Si vous avez besoin d'une autre courbe, vous pouvez également en implémenter une vous-même et l'enregistrer avec [[QEasingCurve]]. ==== Jouer des animations simultanément ==== Une application contiendra souvent plus d'une animation. Par exemple, vous pouvez vouloir déplacer plus d'un élément graphique simultanément ou les déplacer en séquence les uns après les autres. Les sous-classes de [[QAnimationGroup]] ([[QSequentialAnimationGroup]] et [[QParallelAnimationGroup]]) sont des conteneurs pour d'autres animations, pour que celles-ci puissent être animées en séquence ou parallèlement. Le [[QAnimationGroup]] est un exemple d'animation qui n'anime pas les propriétés, mais il reçoit la notification de changement de temps périodiquement. Cela lui permet de transmettre ces changements de temps à ses animations contenues, et ainsi contrôler quand celles-ci sont jouées. Regardons les exemples de code qui utilisent à la fois [[QSequentialAnimationGroup]] et [[QParallelAnimationGroup]], en commençant par ce dernier. 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(); Un groupe parallèle joue plus d'une animation à la fois. L'appel à sa fonction [[qabstractanimation#start|start()]] débutera toutes les animations qu'il gouverne. 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(); Comme vous l'avez sans doute deviné, [[QSequentialAnimationGroup]] joue ses animations en séquence (dans l'ordre). Il commence l'animation suivante dans la liste après que la précédente soit terminée. Puisqu'un groupe d'animations est une animation lui-même, vous pouvez l'ajouter à un autre groupe. De cette façon, vous pouvez construire une structure arborescente des animations qui spécifie quand celles-ci sont jouées les unes par rapport aux autres. ==== Machine à état et animations ==== Lorsque vous utilisez une machine d'état, il est possible d'associer une ou plusieurs animations à une transition entre états en utilisant la classe [[QSignalTransition]] ou [[QEventTransition]]. Ces classes sont toutes deux dérivées de [[QAbstractTransition]], qui définit la fonction adéquate [[qabstracttransition#addAnimation|addAnimation()]] permettant l'apposition d'une ou plusieurs animations déclenchées lorsque la transition se produit. Nous avons également la possibilité d'associer les propriétés avec les états plutôt que de fixer la valeur de début et la valeur de fin nous-même. Voici un exemple de code complet qui anime la géométrie d'un [[QPushButton]]. QPushButton *button = new QPushButton("Animated Button"); button->show(); QStateMachine *machine = new QStateMachine; QState *state1 = new QState(machine->rootState()); state1->assignProperty(button, "geometry", QRect(0, 0, 100, 30)); machine->setInitialState(state1); QState *state2 = new QState(machine->rootState()); state2->assignProperty(button, "geometry", QRect(250, 250, 100, 30)); QSignalTransition *transition1 = state1->addTransition(button, SIGNAL(clicked()), state2); transition1->addAnimation(new QPropertyAnimation(button, "geometry")); QSignalTransition *transition2 = state2->addTransition(button, SIGNAL(clicked()), state1); transition2->addAnimation(new QPropertyAnimation(button, "geometry")); machine->start(); Pour un exemple plus complet sur la façon d'utiliser le framework de la machine à état, voir l'exemple des états (il est présent dans le répertoire ''examples/animation/states''). ==== Remerciements ==== Merci à pour la traduction et à et à pour leur relecture !