Tuto - Comment faire communiquer Qml et C++ ?

Il s’agit ici d’illustrer comment mettre en place une interaction entre la partie graphique de l’application (qml) et des classes C++ qui gèrent la logique de l’application. L’application développée consiste en un compteur graphique que l’on peut incrémenter ou décrémenter avec les flèches du clavier.

compteur graphique


1. Arbre de scène de notre application (Qml - partie statique)

  • Créer un projet Qt Quick Application appelé Compteur2024. Notez l’emplacement de votre projet sur votre DD.
  • Compilez et exécutez le projet (flèche verte dans le bandeau latéral gauche de l’application).
  • Sélectionnez le fichier Main.qml et passez en mode Design. Utilisez le menu Affichage/Vue pour construire une fenêtre ressemblant à la figure ci-dessous (pour cela, sélectionnez ‘2D’ et ‘Propriétés’).

Vue du mode _Desing_ de _QT Cretator_

  • Nettoyage de l’application par défaut
    • Dans la colonne Properties, modifiez la taille par 320 et 240. La Colonne Code est automatiquement mise à jour.
    • Modifier la couleur blanche avec un couleur de votre choix en naviguant dans les propriétés. Profitez-en pour tester différentes propriétés (taille du bord…).
    • En effectautn un Drag and Drop à partir des composants, ajouter un rectangle de taille 100x50, centré dans la fenêtre (pour cela, modifiez Anchors dans le tab layout de la colonne Properties), dont la couleur contraste avec la couleur de fond.
    • Ajouter un Text centré dans ce rectangle, de taille 100x50 (il couvre ainsi tout le rectangle), centré en largeur, et centré en hauteur, police Tahoma, grasse, taille 20.
    • Cochez focus: true (cette option est cachée en bas de la colonne Properties/Advanced).

À ce stade, vous devriez avoir quelque chose qui ressemble à cela:

Vue du mode _Design_ de notre Compteur

Nous en avons terminé avec la partie statique de l’application (appelé arbre de scène graphique), passons maintenant aux interactions entre l’interface et les actions de l’utilisateur.


2. Programme principal et classe Compteur

  • Revenez au mode Modifier et sélectionner le fichier main.cpp. Lancez votre programme pour voir l’interface graphique que nous venons de créer.
  • Créer une classe Compteur, héritée de la classe QObject (la case ‘Add Q_OBJECT’ doit être cochée).
  • Retrouver le fichier main.cpp dans l’arborescence du projet et remplacez le programme principal par celui-ci (les 4 lignes ajoutées sont mises en évidence par un commentaire : // <– AJOUT ICI):
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>                // <-- AJOUT ICI
#include "compteur.h"                 // <-- AJOUT ICI

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    Compteur aCompteur ;               // <-- AJOUT ICI

    QQmlApplicationEngine engine;
    QObject::connect(
        &engine,
        &QQmlApplicationEngine::objectCreationFailed,
        &app,
        []() { QCoreApplication::exit(-1); },
        Qt::QueuedConnection);
    engine.rootContext()->setContextProperty("vueObjetCpt", &aCompteur); // <-- AJOUT ICI
    engine.loadFromModule("Compteur2025", "Main");

    return app.exec();
}

Les ajouts permettent de créer un objet aCompteur, que l’on associe à "vueObjetCpt", ce dernier désignant le nom de notre objet dans le code Qml.

Exécutez votre programme pour vérifier que tout se passe bien (aucun changement apparent à ce stade).


3. Partie dynamique : gestion des flèches.

Basculer dans Design.

  • Après avoir sélectionné le fichier Main.qml, passez en mode Design, et remplacer le texte text: qsTr(“Text”) de l’objet Text par ces quelques lignes :
text: vueObjetCpt.cptQML
Keys.onPressed: (event)=> {
  switch (event.key) {
    case Qt.Key_Up:
      vueObjetCpt.increment();
      break;
    case Qt.Key_Down:
      vueObjetCpt.decrement();
      break;
  }
}

Le terme vueObjetCpt est le nom donné à votre objet aCompteur dans qml (cf main.cpp). Nous venons d’introduire un attribut (cptQML) et 2 méthodes (increment() et decrement()) que nous allons maintenant programmer dans la classe Compteur.

  • Passer en mode Modifier et sélectionnez le fichier d’entête de la classe Compteur.

    • Créer un attribut privé int fCompteur; dans une nouvelle section private:, l’initialiser à 10 dans le constructeur de la classe.
    • Créer les deux méthodes d’incrémentation et de décrémentation du compteur :
      • Dans compteur.h, partie publique, ajouter :
Q_INVOKABLE void increment();
Q_INVOKABLE void decrement();
    - Dans _compteur.cpp_, ajouter :
void Compteur::increment(){
    fCompteur++;
}

void Compteur::decrement(){
    fCompteur--;
}

4. Établir la communication entre Qml et C++

Créer un Q_PROPERTY dans compteur.h, dans la partie publique (cf doc QT) :

Q_PROPERTY(QString cptQML READ readCompteur NOTIFY cptChanged)

Attention : il n’y a pas de ; à la fin de ligne.
Explications : La propriété cptQML est un QString (essentiellement une chaîne de caractères). Quand un signal cptChanged a été envoyé (et donc que la variable fCompteur a été changée), alors on peut obtenir sa valeur à l’aide de la méthode readCompteur (qui doit donc renvoyer un QString).

  • Ajouter la méthode privée readCompteur dans compteur.cpp:
QString Compteur::readCompteur() {
    return QString::number(fCompteur);
}

N’oubliez pas de déclarer la méthode dans compteur.h, partie private. Cette méthode est utilisée par l’interface graphique pour lire la valeur contenue dans la variable fCompteur. La variable (entière) est d’abord transformée en chaîne de caractères. - Créer le signal suivant dans compteur.h (section signals:) :

void cptChanged();

Ce signal doit être envoyé dès lors que le compteur change : il faut en informer l’interface graphique pour qu’elle lise la nouvelle valeur du compteur et l’affiche dans l’élément graphique Text. En conséquence, dans compteur.cpp, faites un appel emit cptChanged(); dans les 3 méthodes (après la modification de la variable fCompteur).

  • Exécutez le programme et vérifiez que vous pouvez manipuler le compteur avec les flèches.

Question Comment bloquer le compteur à des valeurs comprises entre 5 et 15 ?