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 :

import Qt 4.6

    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 :

import Qt 4.6

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.

Rectangle {
    id: page
    width: 500; height: 200
    color: "lightgray"
Nous lui donnons un "id" pour pouvoir y faire référence dans la suite du programme en le nommant "page". Nous changeons également sa taille ainsi que sa couleur. Un rectangle a d'autres propriétés mais nous les laisserons avec les valeurs par défaut.

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.

    Text {
        id: helloText
        text: "Hello world!"
        font.pointSize: 24; font.bold: true
        y: 30; anchors.horizontalCenter: page.horizontalCenter
    }
L'une des propriétés importantes est "anchors.horizontalCenter", dans ce cas, il permet de centrer horizontalement le Text par rapport au Rectangle que nous avons nommé "page" précédement.

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.

import Qt 4.6

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.

Item {
    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.

property alias color: rectangle.color

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.

signal clicked(color color)

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.

    Rectangle {
        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.

    MouseRegion {
        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.

import Qt 4.6

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.

Cell { color: "red"; onClicked: helloText.color = color }

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 :

import Qt 4.6

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.

        states: State {
            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.

        transitions: Transition {
            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