Introduction à QML et à ses Composants de Base

Ancrages (Anchors)

  • left : Bord gauche
  • right : Bord droit
  • top : Bord supérieur
  • bottom : Bord inférieur
  • centerIn : Centré dans le parent
  • fill : Remplir complètement le parent
  • verticalCenter : Centré verticalement
  • horizontalCenter : Centré horizontalement

Exemple d'ancrage :

parent.anchors.left: parent // Positionne l'élément sur le bord gauche de son parent

Rotation

La propriété rotation permet de faire pivoter un élément instantanément.

Exemple de rotation lors d'un clic :

onClicked: wheel.rotation += 90 // L'objet 'wheel' tourne de 90 degrés lors d'un clic

Animations pour la Rotation

Pour rendre la rotation fluide, on utilise des comportements animés.

Image {
    id: rootElement
    Image {
        id: wheel
        // Définit le comportement lors de la modification de la propriété 'rotation'
        Behavior on rotation {
            NumberAnimation {   // Utilise une animation numérique
                duration: 250   // Durée de l'animation : 250 millisecondes
            }
        }
    }
}

Modules Fondamentaux de Qt

Présentation des Modules

Qt est organisé en plusieurs modules qui fournissent des fonctionnalités spécifiques.

Module Description
Qt Core Classes de base non graphiques, essentielles pour les autres modules.
Qt GUI Classes de base pour les interfaces graphiques (GUI), incluant OpenGL.
Qt Multimedia Fonctionnalités pour l'audio, la vidéo, la radio et la caméra.
Qt Network Classes simplifiant la programmation réseau.
Qt QML Support pour les classes QML et le langage JavaScript.
Qt Quick Framework pour la création d'interfaces utilisateur dynamiques et personnalisées.
Qt SQL Classes pour l'intégration avec les bases de données SQL.
Qt Test Classes pour les tests unitaires des applications et bibliothèques Qt.
Qt WebKit Implémentation de base de WebKit2 avec une nouvelle API QML.
Qt WebKit Widgets Classes de base pour les widgets intégrant WebKit1 de Qt4.
Qt Widgets Classes de widgets C++ étendant le module Qt GUI.

Structure des dépendances principales :

Création d'un Projet Qt

Nouveau Projet Qt Quick

Qt Creator propose plusieurs modèles pour démarrer un projet Qt Quick :

  • Swipe : Cadre pour la navigation entre plusieurs pages par balayage, avec des boutons de tabulation.
  • Scroll : Cadre pour des listes déroulantes avec une barre de défilement.
  • Stack : Cadre basé sur une pile, avec une page principale et des sous-pages.
  • Empty : Projet vide, ne contenant qu'une fenêtre "Hello World".

Premier Programme "Hello World"

Créons un projet vide nommé QML_helloworld.

La structure typique d'un tel projet est la suivante :

QML_helloworld
    └─QML_helloworld.pro    // Fichier de projet Qt
     └─Sources
        └─main.cpp              // Fichier C++ principal
     └─Resources
        └─qml.qrc               // Fichier de ressources Qt
            └─/                 
               └─main.qml      // Fichier QML principal

Le fichier main.cpp charge et exécute le fichier QML. Pour lier les données C++ à l'interface QML, il faut explorer la syntaxe QML.

Voici un exemple simple de QML créant un rectangle avec le texte "Hello, World" et une fonctionnalité de sortie :

import QtQuick 2.9
import QtQuick.Window 2.2

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Rectangle {
        width: 360
        height: 360
        color: '#EE00EE' // Couleur violette

        Text {
            id: helloText
            anchors.centerIn: parent
            text: qsTr("Hello, World")
        }

        MouseArea {
            anchors.fill: parent // La zone de clic couvre tout le rectangle
            onClicked: {
                Qt.quit(); // Quitte l'application
            }
        }
    }
}

Avantages de Qt Quick

Qt Quick permet une séparation claire entre le développement front-end (interface utilisateur) et back-end (logique métier). L'interface est définie en QML, un langage déclaratif similaire à HTML, tandis que la logique peut être implémentée en C++. Cela facilite les mises à jour d'interface sans impacter la logique principale.

Débogage (Debugging)

Le débogage QML se fait dans Qt Creator, de manière similaire au débogage C++.

Raccourcis utiles dans Qt Creator :

  • Ctrl+B : Construire le projet
  • Ctrl+R : Exécuter le projet
  • Ctrl+Tab : Changer de document ouvert
  • Ctrl+k : Ouvrir le localisateur
  • Esc : Revenir en arrière
  • F2 : Afficher la définition d'un symbole
  • F4 : Basculer entre fichier d'en-tête et fichier source (pour C++)

Introduction à la Syntaxe QML

Syntaxe Générale

  • import : Importe un module QML et sa version (ex: import QtQuick 2.9).
  • Commentaires : Similaires à C++ et JavaScript (// ou /* */).
  • Éléments : Chaque fichier QML doit avoir un élément racine. Les éléments sont définis par des accolades {}. Les propriétés sont sous la forme nom: valeur. Les éléments peuvent être imbriqués et référencés par leur id. Le mot-clé parent permet d'accéder à l'élément parenet.
  • Aperçu (Preview) : Utilisez qmlscene pour visualiser un fichier QML : $QTDIR/bin/qmlscene mon_fichier.qml.

Caractéristiques des Propriétés

  • id : Identifiant unique d'un élément dans le scope actuel, similaire à un pointeur en C++.
  • Valeurs par défaut : Les propriétés non initialisées prennent une valeur par défaut définie dans la documentation de l'élément.
  • Liaisons de Propriétés (Property Binding) : Une propriété peut dépendre d'autres propriétés. Sa valeur est mise à jour automatiquemant lorsque les propriétés dont elle dépend changent.
  • Propriétés personnalisées : Définies avec le mot-clé property (ex: property int score: 0). Si une propriété est destinée à être la propriété principale, on peut utiliser default.
  • Alias de Propriétés : property alias nom: autreElement.propriete permet d'exposer une propriété d'un sous-élément à l'extérieur du composant.
  • Propriétés groupées : Les propriétés d'un même groupe peuvent être définies de manière compacte (ex: font { family: "Ubuntu"; pixelSize: 24 }).

Signaux

Les signaux sont déclenchés lorsque des événements se produisent, comme le changement d'une propriété.

  • on<Propriete>Changed : Signal émis quand une propriété change (ex: onHeightChanged: console.log('height:', height)).
  • Keys.onSpacePressed : Signal déclenché lors de l'appui sur la barre d'espace.
  • Keys.onEscapePressed : Signal déclenché lors de l'appui sur la touche Échap.

Portée des Identifiants (ID Scope)

Les id sont uniques au sein d'un fichier QML. Pour exposer des éléments à l'extérieur, on utilise des alias ou des propriétés exportées sur l'élément racine. Il faut être prudent avec les mécanismes qui peuvent écraser des IDs lors du chargement dynamique de composants.

Scripts JavaScript

QML peut intégrer du JavaScript pour des logiques plus complexes.

Text {
    id: label
    x: 24; y: 24
    width: 360
    height: 360
    color: '#aaaaaa'
    property int spacePresses: 0
    text: "Space pressed: " + spacePresses + " times" // Liaison de propriété

    onTextChanged: console.log("text changed to: ", text)

    focus: true // Nécessaire pour recevoir les événements clavier

    Keys.onSpacePressed: {
        increment() // Appel de la fonction JavaScript
    }
    Keys.onEscapePressed: {
        label.text = '' // Affectation simple, rompt la liaison de propriété précédente
    }

    function increment() {
        spacePresses = spacePresses + 1 // Affectation simple
    }
}

Notez la différence entre l'affectation simple (= dans une fonction JavaScript) qui n'est exécutée qu'une fois, et la liaison de propriété qui est active pendant toute la durée de vie de l'élément.

Éléments de Base

Types d'Éléments

  • Visuels : Ont une représentation graphique (ex: Rectangle, Text, Image).
  • Non-visuels : Fournissent des fonctionnalités (ex: Timer).

Éléments Visuels Courants

  • Item : L'élément de base de tous les éléments visuels. Il ne dessine rien mais définit les propriétés communes (position, taille, ancrages, transformations, visibilité, états). Il sert souvent de conteneur.
  • Rectangle : Étend Item en ajoutant la possibilité de remplir avec une couleur et de définir des bordures et des coins arrondis.
  • Text : Affiche du texte. Les propriétés comme font, color, horizontalAlignment, verticalAlignment contrôlent son apparence.
  • Image : Affiche des images. La propriété source spécifie le fichier image, et fillMode contrôle comment l'image est adaptée.
  • MouseArea : Permet de capturer les événements de souris pour un élément, sans être visible elle-même.

Item (l'Élément de Base)

Propriétés communes des éléments visuels :

  • Géométrie : x, y, width, height, z (ordre d'empilement).
  • Mise en page : anchors (positionnement par rapport au parent ou à d'autres éléments), margins.
  • Gestion clavier : focus, Keys.
  • Transformations : scale, rotation, transformOrigin.
  • Visuel : opacity, visible, clip, smooth.
  • États : states, transitions pour gérer les changements d'état animés.

Rectangle (Élément Rectangulaire)

Permet de créer des formes rectangulaires colorées avec des bordures et des coins arrondis.

Rectangle {
    id: rect1
    x: 10; y: 10
    width: 75; height: 95
    color: "lightsteelblue" // Couleur unie
}
Rectangle {
    id: rect2
    x: 110; y: 12
    width: 75; height: 95
    color: "white"
    border.color: "lightsteelblue"
    border.width: 5
    radius: 8 // Coins arrondis
}

Les couleurs peuvent être spécifiées par nom, hexadécimal (#RRGGBB) ou RGB. Les dégradés sont possibles avec la propriété gradient.

Rectangle {
        id: rectGradient
        width: 175; height: 95
        gradient: Gradient { // Définition du dégradé
            GradientStop { position: 0.0; color: "lightsteelblue" }
            GradientStop { position: 0.5; color: "slategray" }
            GradientStop { position: 1.0; color: "lightsteelblue" }
        }
        border.color: "slategray"
    }

Il faut définir width et height pour qu'un rectangle soit visible.

Text (Élément Texte)

Affiche du texte. Les propriétés clés sont text, font (family, pixelSize), color.

Text {
    text: "Bonjour le Monde !"
    font.family: "STXinwei" // Police spécifique (doit être installée sur le système)
    color: "#333333"
    font.pixelSize: 28
}

Il est possible de charger des polices personnalisées avec FontLoader.

Alignement : horizontalAlignment (AlignLeft, AlignHCenter, AlignRight, AlignJustify) et verticalAlignment (AlignTop, AlignVCenter, AlignBottom).

Text {
    x: 50; y: 50
    width: 150; height: 120 // Largeur et hauteur définies pour le retour à la ligne
    text: 'Un texte très long qui doit passer à la ligne'
    wrapMode: Text.WordWrap // Retour à la ligne aux mots
    style: Text.Sunken // Effet de texte enfoncé
    styleColor: '#FF4444'
    verticalAlignment: Text.AlignTop
    font.pixelSize: 20
}

Gestion du texte long :

  • elide : Ajoute des points de suspension (ElideMiddle, ElideLeft, ElideRight, ElideNone).
  • wrapMode : Gère le retour à la ligne (WordWrap, WrapAnywhere, NoWrap). Nécessite la définition d'une largeur.

Le Text n'a pas de fond par défaut ; il faut utiliser un Rectangle comme conteneur pour ajouter un fond.

Image (Élément Image)

Affiche des images (PNG, JPG, GIF, etc.).

Image {
    x: 12; y: 12
    source: "image/rocket.png" // Chemin vers l'image
}
Image {
    x: 112; y:12
    width: 48
    height: 118/2
    source: "image/rocket.png"
    fillMode: Image.PreserveAspectCrop // Adaptation avec rognage
    clip: true // Assure que l'image est rognée aux limites de l'élément
}

Propriété fillMode (modes d'adaptation) :

  • Stretch : Étire l'image pour remplir.
  • PreserveAspectFit : Redimensionne uniformément pour tenir sans rogner.
  • PreserveAspectCrop : Redimensionne uniformément pour remplir, en rognant si nécessaire.
  • Tile : Répète l'image horizontalement et verticalement.
  • Pad : Affiche l'image sans transformation.

La propriété clip (activée à true) contraint le dessin de l'élément à ses limites.

MouseArea (Zone Souris)

Un élément non visuel pour capturer les événements de souris (clic, survol, etc.) sur une zone définie.

Rectangle {
    id: rectContainer
    width: 100; height: 100
    color: "lightblue"

    MouseArea {
        anchors.fill: parent // La zone souris couvre tout le rectangle parent
        onClicked: console.log("Rectangle clicked!") // Action lors du clic
    }
}

Composants (Components)

Un composant est un élément réutilisable. On peut les créer en créant un fichier QML séparé (ex: Button.qml).

// Button.qml
import QtQuick 2.0

Item { // L'élément racine est un Item, bon pour l'encapsulation
    id: rootComponent
    property alias buttonText: label.text // Expose la propriété 'text' du Text interne
    signal clicked // Définit un signal personnalisé

    Rectangle {
        id: buttonRect
        width: 110; height: 25
        color: "lightsteelblue"
        border.color: "slategrey"

        Text {
            id: label
            anchors.centerIn: parent
            text: "Start" // Valeur par défaut
        }

        MouseArea {
            anchors.fill: parent
            onClicked: {
                statusText.text = "Button clicked!" // Change un texte interne
                rootComponent.clicked() // Émet le signal personnalisé
            }
        }
    }

    Text { // Un élément interne pour montrer le statut
        id: statusText
        x: 10; y: 75
        width: 110; height: 25
        text: "Waiting..."
        horizontalAlignment: Text.AlignHCenter
    }
}

Utilisation du composant Button.qml :

// Fichier principal (ex: main.qml)
import QtQuick 2.9

Window {
    // ... autres propriétés ...

    Button { // Utilisation du composant personnalisé
        id: myButton
        x: 12; y: 12
        buttonText: "Click Me!" // Définit la propriété exposée 'buttonText'
        onClicked: { // Réagit au signal 'clicked' du composant
            statusDisplay.text = "Clicked!"
        }
    }

    Text {
        id: statusDisplay
        x: 12; y: 75
        width: 110; height: 25
        text: "Waiting..."
        horizontalAlignment: Text.AlignHCenter
    }
}

Transformations Simples

Les transformations (translation, rotation, échelle) modifient l'apparence des éléments.

Un composant d'image cliquable pour démonstration :

// ClickableImage.qml
import QtQuick 2.0

Image {
    id: root
    signal clicked // Signal pour notifier les clics
    MouseArea {
        anchors.fill: parent
        onClicked: root.clicked() // Émet le signal quand on clique sur l'image
    }
}

Utilisation du composant et application de transformations :

Image { id: bg; source: "image/blue.png" } // Fond d'écran

MouseArea { // Permet de réinitialiser les transformations en cliquant sur le fond
    anchors.fill: parent
    onClicked:  {
        rocket1.x = 20
        rocket2.rotation = 0
        rocket3.rotation = 0
        rocket3.scale = 1.0
    }
}

ClickableImage {
    id: rocket1
    x: 20; y: 100
    source: "image/rocket.png"
    onClicked: {
        x += 5 // Déplace l'image vers la droite
    }
}

ClickableImage {
    id: rocket2
    x: 140; y: 100
    source: "image/rocket.png"
    smooth: true // Améliore la qualité du rendu
    onClicked: {
        rotation += 5 // Ajoute 5 degrés à la rotation
    }
}

ClickableImage {
    id: rocket3
    x: 240; y: 100
    source: "image/rocket.png"
    smooth: true
    onClicked: {
        rotation += 5 // Ajoute 5 degrés à la rotation
        scale -= 0.05 // Réduit l'échelle de 0.05
    }
}

Ordre d'empilement (Z-order) : Les éléments sont dessinés dans l'ordre où ils apparaissent dans le code. Les éléments ultérieurs sont au-dessus des précédents. La propriété z peut être utilisée pour contrôler explicitement cet ordre.

Éléments de Positionnement

Qt Quick fournit des conteneurs pour organiser automatiquement les éléments enfants : Row, Column, Grid, Flow.

Créons quelques composants de base pour l'exemple :

// RedSquare.qml
import QtQuick 2.0
Rectangle {
    width: 48; height: 48; color: "#ee0000"
    border.color: Qt.lighter(color)
}

Column (Disposition Colonne)

Organise les enfants verticalement avec un espacement.

Rectangle { // Conteneur principal
    width: 150; height: 300
    anchors.centerIn: parent

    Column {
        anchors.centerIn: parent
        spacing: 10  // Espacement entre les lignes
        RedSquare {}
        GreenSquare { width: 100 } // Les tailles peuvent être spécifiées
        BlueSquare {}
    }
}

Row (Disposition Ligne)

Organise les enfants horizontalement avec un espacement.

Rectangle { // Conteneur principal
    width: 300; height: 240
    anchors.centerIn: parent

    Row {
        anchors.centerIn: parent
        spacing: 15  // Espacement entre les colonnes
        RedSquare {}
        GreenSquare {}
        BlueSquare {}
        LighterSquare {}
    }
}

Grid (Disposition Grille)

Organise les enfants en grille avec un nombre défini de lignes et de colonnes.

Rectangle { // Conteneur principal
    width: 300; height: 240
    anchors.centerIn: parent

    Grid {
        rows: 2
        columns: 2
        anchors.centerIn: parent
        spacing: 15
        RedSquare {}
        GreenSquare {}
        BlueSquare {}
        LighterSquare {}
    }
}

Flow (Disposition Flux)

Similaire à Grid mais s'adapte intelligemment à la largeur et la hauteur des éléments.

Rectangle { // Conteneur principal
    width: 300; height: 240
    anchors.centerIn: parent

    Flow {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15
        RedSquare { width: 20 }
        GreenSquare { height: 60 }
        BlueSquare { width: 75 }
        LighterSquare { height: 90 }
    }
}

Repeater (Répéteur)

Utilisé pour créer plusieurs instances d'un élément, souvent en combinaison avec des dispositions.

Points Clés

  • La concaténation d'un entier et d'une chaîne de caractères avec + convertit automatiquement l'entier en chaîne.
  • Pour rendre un élément réactif aux événements clavier, il faut définir focus: true. La couleur peut changer en fonction de l'état de focus : color: focus ? "red" : "black".

Étiquettes: QML Qt Quick Qt Développement UI programmation

Publié le 7 juin à 04h40