Introduction à Qt QuickAperçuQML est un langage scripté de haut niveau. Ses commandes, ou plus précisément, ses éléments, associés à la puissance et à l'efficacité des bibliothèques Qt, rendent la programmation plus intuitive. Dessiner un rectangle, afficher une image à une position donnée, etc. : derrière ces éléments se trouvent des bibliothèques C++ complexes qui effectuent ces actions efficacement. Comme pour toute application graphique, restez conscients que cette facilité à construire des applications graphiques riches signifie qu'une attention particulière peut être nécessaire pour prévenir des problèmes de performances. Le langage permet également de rendre ces commandes plus flexibles par l'utilisation de JavaScript plutôt que de C++ lors de l'ajout de nouvelles couches de logique à votre application. Le JavaScript est plus facile à apprendre que le C++ et peut être intégré dans les fichiers QML ou importé à partir d'un fichier distinct. En QML les divers types d'« objets » sont appelés des éléments. Un élément contient habituellement des propriétés qui aident à définir l'élément. Par exemple, si nous créons un élément appelé Cercle alors le rayon du cercle serait une propriété. Un premier regardLa syntaxe basique d'un élément est SomeElement { id: myObject ... d'autres choses ici ... } Nous définissons ici un nouvel objet. Nous spécifions d'abord son type comme étant SomeElement. Ensuite, entre accolades { ... } nous spécifions les différentes parties de notre élément. L'id est un identifiant unique de l'élément, il doit commencer par une lettre minuscule et ne contenir que des lettres, nombres et tirets bas. C'est le nom de l'objet. Si cet élément SomeElement avait été un Rectangle et qu'il en existait plusieurs, alors l'identifiant unique optionnel nous aurait permis de manipuler chaque élément individuellement. Chaque élément visuel est directement ou indirectement basé sur un, ou hérité d'un, élément appelé Item. Item possède certaines propriétés et actions utiles. Les propriétés possèdent des valeurs par défaut permettant de ne spécifier que celles dont vous avez besoin. Prenons un élément simple tel que Rectangle. Il possède un id, que nous allons appeler myRectangle, il a une largeur width et une hauteur height. Imaginez que vous souhaitiez un rectangle de 500 pixels de large sur 400 de haut. Nous pouvons l'implémenter avec Rectangle et ses propriétés de cette façon : import QtQuick 1.0 // Ceci est un commentaire. Et ci-dessous myRectangle est défini. Rectangle { id: myRectangle width: 500 height: 400 } C'est un script QML valide. Pour l'exécuter, copiez-le et sauvegardez-le dans un fichier myexample.qml par exemple et dans la ligne de commande, entrez : qmlviewer myexample.qml Sur Mac OS X, ouvrez à la place l'application « QMLViewer » et chargez le fichier myexample.qml ou exécutez-le en ligne de commande avec : QMLViewer.app/Contents/MacOS/QMLViewer myexample.qml Cela créera un rectangle très peu intéressant, affiché dans sa propre fenêtre. Hello World!Maintenant, nous voulons ajouter un peu de couleur et de texte pour faire notre programme QML Hello World. Rectangle possède une propriété color pour produire une couleur de fond. Le texte est géré par un élément différent appelé Text. Nous devons créer un objet Text à l'intérieur du Rectangle et définir sa propriété text à « Hello World! ». Donc, pour avoir le texte « Hello world » et la couleur de fond grise, il faut le code suivant : import QtQuick 1.0 Rectangle { id: myRectangle width: 500 height: 400 Text { text: "Hello World!" } color: "lightgray" } Encore Hello WorldÀ partir de maintenant, nous n'allons plus systématiquement montrer la ligne d'importation pour Qt mais elle doit toujours être là lorsque vous créez des scripts QML. Pour rendre notre exemple d'Hello World un peu plus beau, définissez la position du texte à la position de pixel x = 100, y = 100 de la fenêtre affichée. La position appartient à l'élément Text donc nous définissons la position à l'intérieur de sa définition. Notez que nous séparons les différentes commandes d'une même ligne avec l'aide d'un point virgule ou alors, nous pouvons mettre une commande par ligne : Text { text: "<h2>Hello World</h2>"; color: "darkgreen" x: 100; y:100 } Nous n'avons pas seulement repositionné le texte mais aussi ajouté des balises HTML pour changer la taille du texte. La couleur du texte a aussi été modifiée pour devenir vert foncé en utilisant un mot-clé standard du SVG pour les noms de couleur. Nous aurions aussi pu utiliser une chaine de caractères hexadécimale pour les valeurs RGB de la couleur (rouge-vert-bleu, comme #rrggbb), ce qui est similaire à la méthode utilisée en HTML. Par exemple, une couleur presque bleue avec un peu de vert : Text { text: "<h1>Hello world again</h1>" color: "#002288" x: 100; y: 100 } Tous ces changements ont été faits à l'intérieur de l'objet Text qui est le champ d'action de ces changements de propriétés. Les autres objets peuvent utiliser les informations mais elles appartiennent à l'élément dans lequel les propriétés ont été définies. ImagesPour ajouter une image à notre petite application, nous utilisons l'élément Image. Une Image utilise un chemin vers un fichier image et possède des propriétés pour contrôler les proportions, la taille de l'image, le pavage de la zone, etc. La source de l'image (le chemin vers le fichier) est une URL. Ainsi le fichier peut être local : mydir/myimage1.png, ou il peut être distant : « http://www.example.com/images/myimage1.png ». Image { source: "images/qt-logo.svg" } Cela affiche une image, comme nous l'attendions, dans le coin supérieur gauche de la fenêtre. La position par défaut est x = 0, y = 0. Cet exemple utilise un fichier SVG mais nous aurions pu utiliser l'un des nombreux autres formats acceptés, incluant le PNG, JPG et GIF. Repositionnons l'image et agrandissons-la. Plaçons-la à la même position en x que le texte « Hello world again » mais plaçons-la 50 pixels en dessous du texte, puis donnons-lui une taille de 150 par 150 pixels : Image { source: "images/qt-logo.svg" x: 100; y: 150 width: 150; height: 150 } En regroupant tout ce que nous avons vu, nous pouvons écrire un petit fichier QML qui commence à ressembler à quelque chose. import QtQuick 1.0 Rectangle { id: myRectangle width: 500 height: 400 Text { text: "<h1>Hello world again</h1>" color: "#002288" x: 100; y: 100 } Image { source: "images/qt-logo.svg" x: 100; y: 150 width: 150; height: 150 } color: "lightgray" } Le résultat reste simple. Ancres : Aligner des élémentsL'utilisation du positionnement absolu, tel que x = 100 et y = 150, fonctionne bien tant que l'utilisateur ou le développeur ne modifie pas la taille de la fenêtre. Si cela arrive, les positions doivent être recalculées. Une bonne chose serait d'avoir un positionnement relatif des objets dans la fenêtre ou le rectangle. Par exemple, si nous voulons placer une image en bas du rectangle, nous aimerions spécifier l'emplacement de l'image comme le bas de la fenêtre et non en utilisant des coordonnées. Nous pouvons le faire avec les propriétés d'ancres, que les objets possèdent grâce à l'héritage d'Item. Les propriétés d'ancres sont en fait un groupe de propriétés. C'est un ensemble de propriétés liées. Il contient des propriétés pouvant être utilisées grâce à la notation « point ». La notation « point » utilise l'identifiant id de l'objet et les noms de propriétés pour utiliser un objet ou une propriété particulière. Mettons que nous ayons un rectangle r1, contenant un rectangle r2, contenant un élément item1, qui possède une propriété x que nous souhaitons changer. Nous pouvons identifier celle-ci avec la notation « point »: r1.r2.item1.x Si nous souhaitons positionner l'image en bas du rectangle dans lequel elle se situe, nous devons spécifier que le bas de l'image est en bas du rectangle : import QtQuick 1.0 Rectangle { id: myWin width: 500 height: 400 Image { id: image1 source: "images/qt-logo.svg" width: 150; height: 150 anchors.bottom: myWin.bottom } } Cela place le logo en bas à gauche de la fenêtre. Nous aimerions que l'image soit centrée et ne touchant pas le bas de la fenêtre, pour des raisons esthétiques. Pour le centrage nous utilisons la propriété horizontalCenter et pour éviter que l'image ne touche le bas du rectangle, la propriété bottomMargin est utilisée. Donc les nouvelles actions du script sont :
En script QML cela devient : import QtQuick 1.0 Rectangle { id: myWin width: 500 height: 400 Image { id: image1 source: "images/qt-logo.svg" width: 150; height: 150 anchors.bottom: myWin.bottom anchors.horizontalCenter: myWin.horizontalCenter anchors.bottomMargin: 10 } } Exécutez ceci et redimensionnez la fenêtre. Vous allez voir que la position de l'image s'ajuste durant le redimensionnement. Vous pouvez aussi ajouter un autre objet, disons un texte descriptif et le placer au-dessus, en dessous, ou à côté de l'image. Le code suivant place le texte juste au dessus de l'image : Text { text: "<h2>The Qt Logo</h2>" anchors.bottom: image1.top anchors.horizontalCenter: myWin.horizontalCenter anchors.bottomMargin: 15 } Note : anchors est un groupe de propriétés, à utiliser à l'intérieur de l'objet. Lors du référencement de ces propriétés dans un autre objet, nous utilisons la propriété directement, à la place de : myRectangle.anchors.top // Faux nous utilisons myRectangle.top // Juste TransformationsNous pouvons transformer un objet graphique pour obtenir des effets supplémentaires. Tourner un texte de 180 degrés pour l'afficher renversé, tourner une image de 90 degrés pour la coucher sur le côté : ces transformations demandent des informations supplémentaires. Pour les rotations, les informations supplémentaires sont : le point d'origine, l'axe de rotation et l'angle de rotation en degrés dans le sens horaire. L'axe n'est pas obligatoirement l'axe z, la ligne entre vos yeux et l'image, il peut être autour de l'axe vertical y ou de l'axe horizontal x. Nous avons trois dimensions à notre disposition. Afin de simplifier l'exemple, nous tournons de 90 degrés autour de l'axe z dans le sens antihoraire. Nous avons suggéré une rotation du texte. Il peut être utile de redimensionner le texte, et nous pouvons faire les deux. La propriété transform est une liste liste d'éléments Transform, donc en utilisant la syntaxe des listes : myList: [ listElement1, listElement2, ... } ] nous pouvons produire une liste de transformations. Le texte va être tourné de 45 degrés dans le sens antihoraire, agrandi verticalement d'un facteur 1,5 et horizontalement d'un facteur 1,2. En utilisant comme base l'exemple précédent, nous avons : import QtQuick 1.0 Rectangle { id: myWin width: 500 height: 400 Image { id: image1 source: "images/qt-logo.svg" width: 150; height: 150 anchors.bottom: myWin.bottom anchors.horizontalCenter: myWin.horizontalCenter anchors.bottomMargin: 10 transform: Rotation { origin.x: 75; origin.y: 75 axis{ x: 0; y: 0; z:1 } angle: -90 } } Text { text: "<h2>The Qt Logo -- taking it easy</h2>" anchors.bottom: image1.top anchors.horizontalCenter: myWin.horizontalCenter anchors.bottomMargin: 15 transform: [ Scale { xScale: 1.5; yScale: 1.2 } , Rotation { origin.x: 75; origin.y: 75 axis{ x: 0; y: 0; z:1 } angle: -45 } ] } } Le bloc de code dans image1 commençant par transform spécifie que la propriété transform est une Rotation de -90 degrés, c'est-à-dire antihoraire, autour de l'axe z, passant par le centre de l'image, c'est dire la position (75, 75) car l'image est de 150 × 150 pixels. L'autre transformation disponible est Translate. Elle entraine un changement de position de l'élément. Note : dans une liste de transformations, l'ordre des transformations est important. Dans l'exemple ci-dessus, essayez d'inverser le redimensionnement avec la rotation, sans oublier d'enlever ou ajouter une virgule. Les deux résultats sont acceptables pour notre petit test, mais ils sont différents. AnimationsUne animation en QML est effectuée en animant les propriétés des objets. Les propriétés sont des nombres, couleurs, Rectangles, points et directions. Dans QML ce sont des types basiques de QML nommés real, int, color, rect, point, size et vector3d. Il y a différentes possibilités pour créer une animation. Nous allons en voir quelques-unes. Animation numériquePrécédemment, nous avons utilisé une rotation pour changer l'orientation de l'image. Nous pourrions facilement animer cette rotation, en remplaçant la rotation directe de l'élément de 90 degrés par une rotation animée de l'image sur 360 degrés. L'axe de la rotation ne changera pas, la position du centre de l'image non plus. Dans ce cas, une NumberAnimation de l'angle de rotation suffira. Si nous souhaitons une simple rotation autour du centre de l'image alors nous pouvons utiliser la propriété rotation héritée de Item. La propriété rotation est un nombre réel qui indique l'angle de rotation de l'objet dans le sens horaire. Voici le code de notre image animée d'une rotation : import QtQuick 1.0 Rectangle { id: mainRec width: 600 height: 400 Image { id: image1 source: "images/qt-logo.svg" x: 200; y: 100 width: 100; height: 100 // Anime la rotation transformOrigin: Item.Center NumberAnimation on rotation { from: 0; to: 360 duration: 2000 loops: Animation.Infinite } } } Le transformOrigin: Item.Center est redondant car c'est la valeur par défaut de la rotation. Mais si vous changez Center en BottomRight vous verrez une variation intéressante. De plus, si une transformation Rotation avait été utilisée alors nous aurions pu avoir plus de contrôle sur les différents paramètres. Nous pouvions varier l'axe, pour non seulement pouvoir déplacer l'axe z, mais pouvoir utiliser l'axe y, l'axe x, ou une de leurs combinaisons. Par exemple, si notre objectif est d'animer une rotation à partir du centre de l'image autour de l'axe y, nous aurions le code suivant : import QtQuick 1.0 Rectangle { id: mainRec width: 600 height: 400 Image { id: image1 source: "images/qt-logo.svg" x: 200; y: 100 width: 100; height: 100 // Anime la rotation transform: Rotation { origin.x: 50; origin.y: 50; axis {x:0; y:1; z:0} angle:0 NumberAnimation on angle { from: 0; to: 360; duration: 3000; loops: Animation.Infinite } } } } Nous utilisons un rectangle de 600 sur 400 pixels. Dans ce rectangle une image de 100 par 100 pixels est insérée. Elle est tournée en son centre autour de l'axe y, ce qui a l'apparence d'une rotation autour d'un fil vertical invisible auquel l'image serait suspendue. Le temps de révolution est de 3 secondes (3000 millisecondes). La NumberAnimation est appliquée sur l'angle en partant de 0 (aucun changement) à 360 degrés, revenant au point où elle a commencé. Strictement parlant, il n'est pas nécessaire d'aller de 0 à 360 car cela duplique le même emplacement mais cela rend l'exemple plus facile à lire et ne change rien visuellement. Le nombre de boucles pour l'animation est défini comme Animation.Infinite ce qui signifie que l'animation va s'effectuer indéfiniment. Pour voir une variation intéressante, changez l'axe à axis { x:1; y:1; z:1 }. C'est une ligne allant du centre de l'image vers le bas, à droite et en sortant de l'écran. Bien que le changement soit simple, la rotation semble complexe. Animation séquentiellePour une animation plus complexe nous avons besoin de deux images. La première image sera positionnée au centre d'une fenêtre (Rectangle) et la seconde sera dans le coin supérieur gauche de la fenêtre. L'animation déplacera la deuxième image du coin supérieur gauche au coin inférieur droit. En faisant cela, nous allons animer la position et la taille de l'image. Premièrement, créons deux images : import QtQuick 1.0 Rectangle { id: mainRec width: 600 height: 400 z: 0 Image { id: image1 source: "images/qt-logo.svg" x: 20; y: 20 ; z: 1 width: 100; height: 100 } Image { id: image2 source: "images/qt-logo.svg" width: 100; height: 100 x: (mainRec.width - 100)/2; y: (mainRec.height - 100)/2 z: 2 } } Nous allons ajouter une SequentialAnimation à l'image image1 de x = 20 à la cible x = 450. Les valeurs from seront utilisées car nous répétons l'animation, donc l'objet doit connaitre sa position d'origine, pour les deux axes, x et y. La SequentialAnimation de x sera répétée, grâce à la valeur Animation.Infinite pour la propriété loop qui signifie un cycle infini. De plus il y aura une NumberAnimation pour faire varier la propriété numérique des valeurs de x sur une certaine durée. Après la NumberAnimation il y aura une PauseAnimation qui mettra l'animation en pause pendant 500 millisecondes (une demi-seconde) simplement pour l'effet visuel. Image { id: image1 source: "images/qt-logo.svg" width: 100; height: 100 SequentialAnimation on x { loops: Animation.Infinite NumberAnimation { from: 20; to: 450; easing.type: "InOutQuad"; duration: 2000 } PauseAnimation { duration: 500 } } } Un bloc de code similaire est écrit pour l'animation de la valeur y de la position. Nous allons aussi animer le redimensionnement de l'objet durant son déplacement du coin supérieur gauche au coin inférieur droit de la fenêtre. Il deviendra plus petit avant d'atteindre le milieu, puis grossira. Pour compléter l'animation, nous allons définir les valeurs de z des images. La valeur z indique l'ordre d'empilement. L'axe z indique la direction entre l'écran et vos yeux. La valeur par défaut est 0. Donc si nous définissons le Rectangle avec un z de 0, juste pour être sur, l'image1 à 1 et l'image2 à 2 alors l'image1 sera au fond et l'image2 en premier plan. Lorsque l'image1 passe l'image2, elle va être en dessous. Le code complet ressemble à : import QtQuick 1.0 Rectangle { id: mainRec width: 600 height: 400 z: 0 Image { id: image2 source: "images/qt-logo.svg" width: 100; height: 100 x: (mainRec.width - 100)/2; y: (mainRec.height - 100)/2 z: 2 } Image { id: image1 source: "images/qt-logo.svg" x: 20; y: 20 ; z: 1 width: 100; height: 100 SequentialAnimation on x { loops: Animation.Infinite NumberAnimation { from: 20; to: 450 easing.type: "InOutQuad"; duration: 2000 } PauseAnimation { duration: 500 } } SequentialAnimation on y { loops: Animation.Infinite NumberAnimation { from: 20; to: 250 easing.type: "InOutQuad"; duration: 2000 } PauseAnimation { duration: 500 } } SequentialAnimation on scale { loops: Animation.Infinite NumberAnimation { from: 1; to: 0.5; duration: 1000 } NumberAnimation { from: 0.5; to: 1; duration: 1000 } PauseAnimation { duration: 500 } } } } Le easing.type possède de nombreuses options, exprimées sous forme de chaines de caractères. Il indique les équations utilisées pour décrire l'accélération de la valeur de la propriété, pas forcément une position, en fonction du temps. Par exemple, InOutQuad signifie qu'au début et à la fin de l'animation la vélocité velocity est faible mais que l'accélération et la décélération sont fortes. Tout comme une voiture accélérant au début et décélérant à la fin du voyage, avec la vitesse maximale atteinte au milieu du parcours. Examinez la documentation easing et les différents graphiques qui montrent cet effet. L'axe horizontal, progress, peut être considéré comme le temps. L'axe vertical est la valeur de la propriété. Au cours de cette discussion sur les animations, nous devons aussi décrire trois objets : State, MouseArea et Signals. Bien qu'indépendantes des éléments d'animations, les animations permettent d'illustrer parfaitement ces nouveaux éléments. Résumé des animations
Utilisation des étatsUn état est un ensemble de valeurs définies dans la configuration d'un objet et qui dépend souvent de l'état précédent. Par exemple, un verre peut être dans un état appelé MoitiéPlein s'il a été rempli avec un liquide et qu'il a atteint la moitié de sa capacité. Nous pourrions aussi avoir un état MoitiéVide qui serait un état qui apparaîtrait lorsque la quantité de liquide diminue jusqu'à la moitié de la capacité du verre. Les deux états représentent la même quantité de liquide mais nous les considérons différents. De la même façon, les états dans un programme représentent non seulement des valeurs mais peuvent aussi inclure la façon dont les valeurs ont été atteintes. Lorsqu'un état change une transition se produit. La transition permet d'appliquer des changements ou d'exécuter des actions qui dépendent du mouvement vers ce nouvel état. Par exemple, si nous avons une scène d'un paysage où la variable d'état possède deux états « jour » et « nuit », alors lors du changement d'état vers la « nuit », le ciel deviendra sombre, les étoiles apparaitront, le paysage sera assombri. Et lorsque l'état reviendra à « jour », les changements contraires seront appliqués : le ciel devient bleu, la scène devient verte et le soleil apparaît dans le ciel. Voici un programme QML simple montrant le changement d'état de l'exemple ci-dessus. Nous avons deux rectangles, celui du haut est le ciel (sky) et celui du bas le sol (ground). Nous voulons animer le changement du jour vers la nuit. Il y aura deux états mais nous en définissons seulement un seul car le jour (daylight) est l'état par défaut. Nous allons juste aller vers la nuit (night) en cliquant et maintenant le bouton gauche de la souris. Le relâchement du bouton inversera le processus. import QtQuick 1.0 Rectangle { id: mainRectangle width: 600 height: 400 color: "black" Rectangle { id: sky width: 600 height: 200 y: 0 color: "lightblue" } Rectangle { id: ground width: 600; height: 200 y: 200 color: "green" } MouseArea { id: mousearea anchors.fill: mainRectangle } states: [ State { name: "night" when: mousearea.pressed == true PropertyChanges { target: sky; color: "darkblue" } PropertyChanges { target: ground; color: "black" } }, State { name: "daylight" when: mousearea.pressed == false PropertyChanges { target: sky; color: "lightblue" } PropertyChanges { target: ground; color: "green" } } ] transitions: [ Transition { from: "daylight"; to: "night" ColorAnimation { duration: 1000 } }, Transition { from: "night"; to: "daylight" ColorAnimation { duration: 500 } } ] } Plusieurs nouveaux éléments sont apparus dans cet exemple. Premièrement, nous utilisons un élément MouseArea pour détecter le clic sur la souris dans le rectangle mainRectangle. Deuxièmement, nous utilisons une notation de liste [ thing1 , thing2, ... ] pour construire une liste d'états et une liste de transitions. MouseArea définit une région qui répondra aux clics de souris. Dans ce cas nous nous intéressons seulement au fait qu'un des boutons de la souris soit appuyé ou non, sans nous soucier de quel bouton ni des autres détails. La zone de la MouseArea est la fenêtre principale dans son ensemble, donc en cliquant n'importe où dans cette région, l'animation démarrera. Comme nous utilisons seulement l'état de souris appuyé (pressed), l'animation se fera du jour (daylight) à la nuit (night) tant que le bouton de la souris reste appuyé. Lorsque le bouton est relâché, l'état jour (daylight) revient et la transition entre la nuit (night) et le jour est déclenchée, causant l'exécution de l'animation. La transition spécifie la durée en millisecondes de la ColorAnimation, alors que l'état spécifie la couleur du nouvel état. La commande PropertyChanges est le moyen d'indiquer quelles propriétés changent dans un changement d'état et quelles nouvelles valeurs ces propriétés auront. Par exemple, nous voulons pour l'état night que la région sky devienne bleu foncé et que la région ground devienne noire, et donc les rectangles de ces régions sont les cibles (target), et la propriété dans la cible est la couleur (color). SignauxLes signaux sont simplement des évènements qui peuvent être attachés à des actions que nous voulons exécuter. En QML ils sont généralement précédés du mot on, par exemple dans l'animation utilisant une MouseArea, le signal était onPressed. Si vous regardez dans la documentation C++ vous allez voir une longue description des signaux et slots. Les signaux sont connectés aux slots. Le signal représente un évènement, et le slot une fonction qui fait quelque chose en fonction de cet évènement. Vous pouvez aussi avoir des signaux connectés à d'autres signaux, faisant qu'un signal (évènement) déclenche un autre signal (évènement) et ainsi de suite. Il est toujours intéressant de savoir ce qui se passe derrière la couche QML, mais pas essentiel pour l'utiliser. La plupart des éléments n'ont pas de signaux associés. Par contre, certains, comme l'élément Audio possèdent plusieurs signaux. Certains signaux de Audio sont utilisés pour représenter des évènements comme le fait que le son est arrêté, que la lecture commence, est mise en pause, ou que l'on atteint la fin du média. Ils permettent au développeur de connecter, par exemple, l'appui d'un bouton de l'interface utilisateur (peut-être une MouseArea) à un code QML qui gérera cet évènement. Analyse d'un exemple: contrôle d'un cadranDans le dossier Qt examples/declarative/ui-components vous pouvez trouver un dossier dialcontrol qui contient l'exemple dialcontrol (contrôle d'un cadran). Pour l'essentiel, cette petite application est constituée d'une glissière (slider) que vous pouvez positionner avec la souris et d'un cadran graphique répondant à la position de la glissière. Le code de cet exemple est séparé en deux parties : Dial.qml et dialcontrol.qml. Dial.qml peut être trouvé dans le sous-dossier content. Il définit un composant Dial similaire à un cadran de compteur de vitesse. Par la suite, l'exemple va contenir un composant glissière qui lorsqu'il sera déplacé, changera la position de l'aiguille sur le cadran. Le code pour le Dial, identifié par le nom du fichier, contient quatre images dont l'ordre de recouvrement est le suivant : le fond (nombres et divisions), l'ombre de l'aiguille, l'aiguille elle-même, et la vitre (glass) recouvrant le cadran (contenant des couches transparentes). L'image needle_shadow.png possède une Rotation affectée à l'attribut transformation transform de l'Image. La rotation est définie pour correspondre à la valeur de l'angle de l'image de l'aiguille needleRotation.angle. L'aiguille et son ombre possèdent la même valeur par défaut x et y mais l'origine de la rotation pour l'aiguille est légèrement différente afin que l'ombre soit visible lorsque l'aiguille bouge. Image { x: 96 y: 35 source: "needle_shadow.png" transform: Rotation { origin.x: 9; origin.y: 67 angle: needleRotation.angle } } Et l'aiguille: Image { id: needle x: 98; y: 33 smooth: true source: "needle.png" transform: Rotation { id: needleRotation origin.x: 5; origin.y: 65 //! [angle de l'aiguille] angle: Math.min(Math.max(-130, root.value*2.6 - 130), 133) Behavior on angle { SpringAnimation { spring: 1.4 damping: .15 } } //! [angle de l'aiguille] } } L'image finale est la vitre qui possède simplement une position définie. Image { x: 21; y: 18; source: "overlay.png" } dialcontrol.qml dans le dossier examples/declarative/ui-components/dialcontrol est le fichier principal de l'exemple. Il définit l'environnement visuel dans lequel le compteur sera placé. Comme le composant Dial et les images résident dans le sous-dossier content nous devons importer celui-ci dans dialcontrol.qml. Donc le début du fichier ressemble à : import QtQuick 1.0 import "content" L'espace visuel est limité à un Rectangle de 300 par 300 pixels ayant une couleur grise. Dans ce rectangle nous avons notre composant Dial et un Rectangle. À l'intérieur du rectangle appelé container se trouve un autre rectangle nommé sans grande originalité slider. Rectangle { color: "#545454" width: 300; height: 300 // Cadran avec une glissière pour l'ajuster Dial { id: dial anchors.centerIn: parent value: slider.x * 100 / (container.width - 34) } Rectangle { id: container anchors { bottom: parent.bottom; left: parent.left right: parent.right; leftMargin: 20; rightMargin: 20 bottomMargin: 10 } height: 16 radius: 8 opacity: 0.7 smooth: true gradient: Gradient { GradientStop { position: 0.0; color: "gray" } GradientStop { position: 1.0; color: "white" } } Rectangle { id: slider x: 1; y: 1; width: 30; height: 14 radius: 6 smooth: true gradient: Gradient { GradientStop { position: 0.0; color: "#424242" } GradientStop { position: 1.0; color: "black" } } MouseArea { anchors.fill: parent anchors.margins: -16 // Étend la zone de la souris largement en dehors du slider drag.target: parent; drag.axis: Drag.XAxis drag.minimumX: 2; drag.maximumX: container.width - 32 } } } QuitButton { anchors.right: parent.right anchors.top: parent.top anchors.margins: 10 } } Le composant, nommé dial, est ancré au centre du rectangle principal. L'attribut value de dial est défini à une valeur basée sur la position horizontale du slider et la largeur de container. Donc le changement de la position du slider changera la valeur value du compteur qui est utilisée dans le cadran pour calculer la rotation de l'image de l'aiguille. Notez cette partie du code dans Dial où le changement de la valeur value modifie la position de l'aiguille : angle: Math.min(Math.max(-130, root.value*2.6 - 130), 133) Behavior on angle { SpringAnimation { spring: 1.4 damping: .15 } } C'est cette partie de needleRotation qui fait tourner l'aiguille et son ombre. SpringAnimation est un élément qui modifie la valeur de rotation angle et imite le comportement oscillatoire de la source, avec la constante spring appropriée pour contrôler l'accélération et le damping pour contrôler la vitesse à laquelle l'effet disparaît. Le container est gris clair avec un dégradé défini avec GradientStop. Le dégradé est appliqué verticalement. Si vous avez besoin d'un dégradé horizontal, vous pouvez appliquer un dégradé vertical et tourner l'élément de 90 degrés. Le slider est gris foncé et possède aussi un dégradé vertical de couleur. La chose la plus importante à propos du slider est qu'il possède une MouseArea, qui spécifie un drag.target sur lui-même suivant l'axe X. Des valeurs minimales et maximales sur l'axe X sont définies, donc nous pouvons cliquer sur le slider et le glisser de gauche à droite dans les limites du container. Le déplacement du slider modifiera l'attribut value dans le cadran Dial comme vu ci-dessus. Notez aussi l'utilisation d'une valeur radius pour un rectangle. Cela produit des coins arrondis. C'est ce qui permet au container et au slider d'afficher des formes rondes plaisantes à l'?il. RemerciementsMerci à Alexandre Laurent pour la traduction ainsi qu'à Ilya Diallo, Jonathan Courtois et Claude Leloup pour leur relecture ! |
Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. | Qt 4.7 | |
Copyright © 2024 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD. | ||
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP ! |