Le QML : les IHM déclaratives selon Qt
Mon premier programme
Le but de cette page est de présenter la création d'un programme simple pour mettre en avant les différentes possibilités offertes par le QML.
Préparation
Tout d'abord, il faut les outils permettant de créer et de lancer un programme. On peut trouver l'IDE correspondant (actuellement en bêta) à cette adresse. Il suffit de l'installer et de lancer le programme pour accèder aux fonctionnalités offertes par le QML. Il faudra ensuite créer un projet "QML Application" nommé "HelloWorld"
Hello world
Ce programme est un simple "hello world" pour introduire les concepts basiques du QML. Cet exemple est tiré du tutorial de Qt, revu et corrigé pour fonctionner avec la nouvelle version.

Capture du rendu à l'écran
Code de cet exemple :
Rectangle {
id: page
width: 500; height: 200
color: "lightgray"
Text {
id: helloText
text: "Hello world!"
font.pointSize: 24; font.bold: true
y: 30; anchors.horizontalCenter: page.horizontalCenter
}
}
Procédure pas à pas
Tout d'abord, nous importons les types dont nous avons besoin dans cet exemple par le code suivant :
Ensuite, la création de l'élément Rectangle. C'est le bloc le plus basique du QML. Si c'est le premier élément créé, il représente la fenêtre.
id: page
width: 500; height: 200
color: "lightgray"
Nous ajoutons ensuite un élément Text qui sera le fils du Rectangle. On change ensuite un certain nombre de ces propriétés pour personaliser le rendu.
id: helloText
text: "Hello world!"
font.pointSize: 24; font.bold: true
y: 30; anchors.horizontalCenter: page.horizontalCenter
}
Il est possible de lancer cet exemple en faisant un Ctrl+R.
Les composants QML
La suite consiste à ajouter la fonction de changement de couleur du texte en cliquant sur un rectangle. Le résultat sera le suivant :

Capture du rendu à l'écran
Création d'un composant personnalisé
Ce composant sera un rectangle de couleur. Il devra recevoir les évènements souris de l'utilisateur. Nous allons donc l'ajouter à notre projet en créant un fichier "Cell.qml" qui contiendra le code suivant. Attention, le nom d'un composant est défini par son nom de fichier et doit commencer par une majuscule.
Item {
id: container
property alias color: rectangle.color
signal clicked(color color)
width: 40; height: 25
Rectangle {
id: rectangle
border.color: "white"
anchors.fill: parent
}
MouseRegion {
anchors.fill: parent
onClicked: container.clicked(container.color)
}
}
Un item est un élément conteneur. Il ne peut pas être affiché en tant que tel mais on peut lui définir des propriétés ainsi que des éléments fils affichables.
id: container
property alias color: rectangle.color
signal clicked(color color)
width: 40; height: 25
Nous déclarons une propriété "color" qui sera fixée à la création de l'élément. Elle est accessible par les autres composants et permet de définir une couleur pour l'affichage de l'élément Rectangle défini plus bas.
Nous ajoutons également un signal qui permettra de prévenir l'application d'un clic en envoyant une couleur en paramètre. Pour plus d'informations sur les signaux, consulter la documentation de Qt ici.
Ensuite, nous créons un Rectangle pour gérer l'affichage. Il a une bordure blanche et il remplit l'espace défini par l'Item (qui est son parent) grâce à la propriété "anchors.fill". Plus d'informations sur les ancrages : ici.
id: rectangle
border.color: "white"
anchors.fill: parent
}
Enfin, une zone permettant de recevoir les évènement souris. Cette zone est de la même taille que le Rectangle ci-dessus. Quand il est cliqué, le "container" envoie un signal contenant la couleur.
anchors.fill: parent
onClicked: container.clicked(container.color)
}
Intégration dans notre exemple
Une fois notre componsant créé, il faut l'ajouter à notre exemple en modifiant le code du fichier HelloWorld.qml.
Rectangle {
id: page
width: 500; height: 200
color: "lightgray"
Text {
id: helloText
text: "Hello world!"
font.pointSize: 24; font.bold: true
y: 30; anchors.horizontalCenter: page.horizontalCenter
}
Grid {
id: colorPicker
anchors.bottom: page.bottom
rows: 2; columns: 3; spacing: 3
Cell { color: "red"; onClicked: helloText.color = color }
Cell { color: "green"; onClicked: helloText.color = color }
Cell { color: "blue"; onClicked: helloText.color = color }
Cell { color: "yellow"; onClicked: helloText.color = color }
Cell { color: "steelblue"; onClicked: helloText.color = color }
Cell { color: "black"; onClicked: helloText.color = color }
}
}
Nous créons donc un sélecteur de couleurs en plaçant 6 éléments "Cell" dans une grille (élément Grid) permettant d'aligner nos composants. Quand un clic sur un élément est reçu, nous changeons la couleur du texte par la couleur passée dans le signal.
Etats et transitions
Dans cette partie, nous allons mettre en oeuvre les états et les transistions pour rajouter du dynamisme à notre application en animant le texte quand l'utilisateur appuie sur le bouton de la souris. L'objectif est de bouger le texte en bas de l'écran avec une rotation et un changement de couleur si l'utilisateur laisse appuyer sur le bouton de la souris sur le texte.

Résultat obtenue
Le code final :
Rectangle {
id: page
width: 500; height: 200
color: "lightgray"
Text {
id: helloText
text: "Hello world!"
font.pointSize: 24; font.bold: true
y: 30; anchors.horizontalCenter: page.horizontalCenter
transformOrigin: Item.Center
MouseRegion { id: mouseRegion; anchors.fill: parent }
states: State {
name: "down"; when: mouseRegion.pressed == true
PropertyChanges { target: helloText; y: 160; rotation: 180; color: "red" }
}
transitions: Transition {
from: ""; to: "down"; reversible: true
ParallelAnimation {
NumberAnimation { matchProperties: "y,rotation"; duration: 500; easing: "InOutQuad" }
ColorAnimation { duration: 500 }
}
}
}
Grid {
id: colorPicker
anchors.bottom: page.bottom
rows: 2; columns: 3; spacing: 3
Cell { color: "red"; onClicked: helloText.color = color }
Cell { color: "green"; onClicked: helloText.color = color }
Cell { color: "blue"; onClicked: helloText.color = color }
Cell { color: "yellow"; onClicked: helloText.color = color }
Cell { color: "steelblue"; onClicked: helloText.color = color }
Cell { color: "black"; onClicked: helloText.color = color }
}
}
Nous commençons par créer un état nommé "down". Il est activé quand un clic est détecté dans la zone de texte et désactivé lors du relâchement. Dans cet état, on change les propriétés du texte.
name: "down"; when: mouseRegion.pressed == true
PropertyChanges { target: helloText; y: 160; rotation: 180; color: "red" }
}
Ensuite, nous définissons la transition entre l'état initial et l'état "down". On commence par fixer une durée car sinon la transistion est instantanée et ne sera pas visible. Ensuite, nous choisissons les animations affichées tout en disant qu'elles doivent être exécutées en parallèle. Il est possible d'utiliser une "SequentialAnimation" à la place de "ParallelAnimation" pour faire le déplacement puis le changement de couleur.
from: ""; to: "down"; reversible: true
ParallelAnimation {
NumberAnimation { matchProperties: "y,rotation"; duration: 500; easing: "InOutQuad" }
ColorAnimation { duration: 500 }
}
}
Pour aller plus loin, la documentation de Qt ici