1er pas en Qt

Dans cette activité vous allez utiliser l’environnement de développement intégré (ou EDI ou IDE en anglais) nommé Qt Creator pour créer des applications graphiques.

Vous serez amenés à l’utiliser fréquemment pour tout ce qui concerne la programmation en langage C ou C++ aussi bien sur PC que sur Raspberry Pi.

Cet IDE a été conçu spécialement pour développer des programmes C++ avec le framework Qt qui est un ensemble de librairies qui permettent — entre autres — de développer des application graphiques, d’accéder par programme à des bases de données ou au réseau, de dessiner sur l’écran (2D ou 3D)…​

💻 Travail n° 1 Conversion °C ↔ °F

Ce travail guidé va vous permettre de coder votre 1ère application Qt.

🎯 Travail à faire :

  1. Exécuter Qt Creator

  2. Créer un projet avec les caractéristiques suivantes :

    1. type : “Qt Widgets Applications” (Fichiers  Nouveau fichier ou projet…​  Projets  Applications  Qt Widget Application)

    2. nom : QConvertisseurTemperature

    3. classe de base : QDialog

      class information
  3. Reproduire l’IHM (Interface Homme Machine) ci-dessous dans l’espace de travail qui s’ouvre lorsqu’on double-clique sur le fichier maingui.ui.

    Le type et le nom à donner à chacun des composants figure dans l’arborescence reproduite sous l’IHM

    ihm travail 01
    IHM
    ihm tree travail 01
    Arborescence des composants graphiques de l’IHM avec leur nom (→ propriété objectName)
  4. Faire un clic droit sur le bouton “Convertir” et choisir l’évènement clicked()

    go to slot
  5. Étudier le code ci-dessous et le reproduire dans la méthode void MainGUI::on_btnConvert_clicked() { …​ } qui s’affiche dans l’éditeur de texte de Qt Creator suite à l’action précédente

    void MainGUI::on_btnConvert_clicked()
    {
        double tC; // température exprimée en °C et à convertir
        double tF; // résultat de la conversion en °F
        bool isOK; // booléen utilisé pour indiquer si la conversion "chaine -> nombre" a réussi
    
        // Lire dans la variable `tC` la valeur saisie dans le champ de la température en °C [->text()]
        // et tenter de la convertir en nombre [.toDouble(&isOK)]
        tC = ui->ledtFromValue->text().toDouble(&isOK);
    
        // SI la conversion a échoué ALORS
        if( !isOK) {
            // Afficher un message d'erreur
            // (nécessite un `#include <QMessageBox>` en début de fichier)
            QMessageBox::critical(this
                , tr("Erreur de saisie")
                , tr("La valeur saisie pour la température\n"
                     "n'est pas valide"
                     )
                , QMessageBox::Ok
                );
            // Effacer le contenu des 2 champs de saisie
            ui->ledtFromValue->clear();
            ui->ledtToValue->clear();
        // SINON
        } else {
            // Convertir la température °C en température °F
            tF = tC * (9/5) + 32;
    
            // Afficher le résultat de conversion [->setText(...)]
            // après l'avoir mis sous forme de chaine de caractères [QString::number(tF)]
            ui->ledtToValue->setText(QString::number(tF));
        }
        // FINSI
    }
  6. Exécuter le programme pour le tester

  7. Faire évoluer le code source du programme de manière à effacer le contenu des 2 champs de saisie lorsqu’on clique sur le bouton “Effacer” de l’IHM

  8. Recoder l’application dans un nouveau projet afin qu’elle permette la conversion dans les 2 sens (°C → °F et °F → °C)

    Ci-dessous figure l’interface graphique de l’application demandée :

    screenshot qconvertisseurtemperatures

    Le design de cette interface vous est donné dans le fichier mainui.ui :

    • L’ouvrir dans QtDesigner

    • Copier/coller l’entièreté du contenu de la boîte de dialogue MainUI dans votre application Qt Widgets

    1. Faire en sorte que l’évènement clicked des 2 “boutons radio” soit connecté au même slot.

    2. Pour détecter l’émetteur réel du signal dans ce slot — c’est-à-dire déterminer si l’utilisateur a choisi une conversion °C → °F ou l’inverser — on pourra utiliser la méthode QObject::sender() :

      if(QObject::sender() == ui->rbtnCversF) { (1)
          // ...
      }
      1 le if est vrai si c’est le radio bouton rbtnCversF qui a déclenché le signal.
    3. Le slot des boutons radio doit simplement modifier le texte de l’unité des champs de saisie et de résultat.

    4. Enfin, dans le slot du bouton “Convertir”, on peut savoir quel bouton radio est actuellement sélectionné en utilisant la méthode isChecked() de l’un des boutons. Dans notre cas où nous n’avons que 2 boutons radio, si une des méthodes renvoie false, c’est que l’autre bouton radio est forcément sélectionné.

      if(ui->rbtnCverF->isChecked()) {
          // Convertir de °C en °F
      } else {
          // Convertir de °F en °C
      }
  9. 🔥 Recoder l’application de manière plus professionnelle en répartissant le code dans plusieurs fichiers.

    Une architecture très commune est de séparer le code qui gère l’interface homme-machine (→ la vue) des données “métier” (→ le modèle). Le lien entre la vue et le modèle est assuré par un code qu’on appelle le contrôleur : on aboutit alors à une architecture dîte MVC (Modèle - Vue - Contrôleur).

    Le diagramme de classes proposé pour cette application figure ci-dessous :

    qconvertisseurtemperatures mvc class diagram

💻 Travail n° 2 Temps de montée en t° d’un ballon d’eau chaude

On vous demande ici de coder par vous-même une application “Qt Widget”.

Ceci comprend :

  • le design de l’IHM

  • la programmation C++ du code associé à cette IHM

🎯 Travail à faire :

Concevoir et coder une application Qt — avec architecture MVC — qui permet de calculer et afficher le temps de montée en température d’un ballon d’eau chaude connaissant :

  • sa contenance (en l)

  • sa puissance (en W)

  • sa température de départ (en °C)

  • sa température d’arrivée (en°C)

Le temps de montée en température d’un ballon d’eau chaude — exprimée en secondes et notée Δt — est déterminée par la formule suivante :

duree echauffement eau

avec :

  • m, la masse d’eau contenue dans le ballon (en kg). Elle se calcule grâce au volume du ballon. En notant VBallon ce volume (en m3), on a : m = ρ × VBallon, où ρ est la masse volumique de l’eau (ρ = 1000 kg/m3).

  • CP, la capacité calorifique de l’eau dans le ballon (en J/kg/°C). CP = 4186 J/kg/°C.

  • ΔT, l’élévation de température c’est-à-dire la différence entre la t° d’arrivée et la t° de départ

  • p, la puissance en W du ballon d’eau chaude

La contenance (en l) du ballon d’eau chaude sera saisie dans une combo box offrant les choix suivants : 15, 30, 40, 50, 65, 75, 80, 100 (choix par défaut ⇒ propriétés currentText et/ou currentIndex), 150, 200, 250 et 300.

La puissance (en W) du ballon d’eau chaude sera saisie dans une spin box dont l’étendue de valeurs ira de 1000 à 3000 avec un pas de 10.

Les températures de départ et d’arrivées (en °C) seront également entrées via des spin boxes :

  • dans un intervalle [0, 60] avec pas de 10 pour la température d’entrée. La valeur par défaut sera de 15°C (propriété value du widget)

  • dans un intervalle [50, 60] avec un pas de 1 pour la température d’arrivée. La valeur par défaut sera de 50°C.

La durée calculée devra être exprimée en heures, minutes, secondes.

Ci-dessous une illustration de ce qui est attendu :

screenshot  qballoneauchaude

On définit une image de fond pour une application Qt en appliquant une feuille de style CSS comme pour un site web.

MainUI::MainUI(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::MainUI)
{
    ui->setupUi(this);

    // Appliquer une feuille de style à la boîte de dialogue pour définir une image d'arrière plan
    setObjectName("body"); (1)
    setStyleSheet("#body {background-image: url(:/img/chauffe-eau.png); background-repeat:no; background-size:100% 100%;}"); (2)

    connect(ui->btnCalculer, &QPushButton::clicked, this, &MainUI::onBtnCalculerClicked);
}
1 on définit un id pour la boîte de dialogue
2 on applique l’image de fond uniquement à cet élement (et donc, pas à ses descendants : goup boxes, spin boxes etc…​ ). L’url indique que l’image utilisée est chargée depuis une ressource embarquée dans l’application (voir menu Add New…​  Qt  Qt resource file) dans QtCreator.

Le diagramme de classes de l’application devra être conforme à ce qui suit :

qballoneauchaude mvc class diagram

Les méthodes des classes ChauffeEau et Utils sont des méthodes statiques.

Cela se note en UML/SysML par un soulignement de la méthode.

Une méthode statique est une méthode de classe qui peut être appelée sans créer d’objet (⇔ sans instancier la classe).

Cela est pratique dans certains cas :

exemple : méthode statique QString:number() de Qt
long a = 63;
QString s = "hex : " + QString::number(a, 16); // s == "hex : 3f" (1)
// Si `number()` n'était pas statique, on devrait écrire :
// QString conv
// QString s = "hex : " + conv.number(a, 16);
1 on convertit 63 en chaîne de caractère hexadécimaux sans avoir à instancier la classe QString au préalable.

Ci-dessous la méthode pour créer et utiliser une méthode statique qui additionne 2 nombres entiers :

fichier calcul.h
class Calcul {
public:
    static int additionner(int a, int b).
};
fichier calcul.cpp
int Calcul::additionner(int a, int b) { (1)
    return a + b;
}
1 ⚠️ le mot clé static ne doit figurer que dans le fichier .h
fichier main.cpp
#include "calcul.h"

int main(void) {
    // Appel sans créer d'objet
    int resultat = Calcul::additionner(3, 5);
}

🞄  🞄  🞄