Vous êtes sur la page 1sur 31

1 Utilisation d’une boîte à outils

1.1 Boîte à outils


– Boîte à outils (toolkit) : cadre de programmation
qui simplifie l’utilisation de composants graphiques
et le gestion de l’événementiel associé pour créer
des interfaces graphiques utilisateur
– En programmation objets, la boîte à outils fournit
ce cadre par des classes à réutiliser :

– une classe de base pour définir une application


graphique : c’est elle qui gère la boucle événe-
mentielle et la distribution des événements
– des classes qui représentent les événements
– une classe de base pour définir la fenêtre prin-
cipale de l’application
– des classes qui définissent les différents com-
posants graphiques : boutons, menus, . . .
– des classes de base pour créer soi-même des
composants

– La boîte à outils fournit aussi des mécanismes pour

– associer une action à l’interaction de l’utilisa-


teur avec l’application et ses composants
– dessiner dans certains composants

1. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


1.2 Qt
– Dans le monde C/C++ il existe plusieurs boîtes à outils libres multi-plateformes

– wxWidgets (wxwidgets.org)
– Qt (www.qt.io) (version commerciale et version open-source)
– GTK+ (gtk.org)
– ...

– Qt est plus qu’une boîte à outils, c’est une plateforme (un peu lourde) de
développement

2. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


Installation de Qt opensource (version 5) :
– Linux

– installer les paquetages de sa distribution (y compris les paquetages de


développement)

– Windows :

– télécharger l’installeur en-ligne www.qt.io/download-qt-installer


et exécuter qt-unified-windows-x86-x.x.x-online.exe
– ou télécharger les binaires hors-ligne www.qt.io/offline-installers
(! 3,7 Go) et exécuter qt-opensource-windows-x86-5.x.x.exe
– installe les bibliothèques Qt et l’IDE QtCreator, par défaut choisissez
l’installation mingwx.x : cocher aussi l’installation de mingwx.x

3. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2 Création d’interface graphique
2.1 Principes
Deux choses principales à faire pour créer une application graphique :
– Créer une classe fenêtre principale qui représente la fenêtre principale, dé-
rivée de la classe fenêtre principale de la boîte à outil :

– cette classe représente l’interface graphique


– elle définit la fenêtre principale (taille, titre, ... ) et son contenu (ses
composants et leur comportement)
– c’est dans son constructeur que l’on construit l’interface graphique (c.-à-d.
les composants et leur comportement)
– elle contient aussi les données de l’application (p.ex. objet métier)

4. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


– Créer un objet application :

– cet objet définit l’application qui gère l’interface graphique : il gère


pour elle les détails de bas niveaux de la boucle événementielle
– c’est en quelque sorte le « programme principal »

– Créer et afficher la fenêtre principale


– Exécuter l’application

5. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.2 Application en Qt
main.cpp :

#include <QApplication> //bibliothèque Qt


#include "mainwindow.h" //fenêtre principale

int main(int argc, char *argv[])


{
QApplication a{argc, argv}; //créer l’application Qt
MainWindow w; //créer la fenêtre principale
w.show(); //l’ouvrir

return a.exec(); //exécuter l’application


}

6. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.3 Fenêtre principale en Qt
On peut créer alors la classe représentant la fenêtre principale, p.ex. MainWindow :

mainwindow.h :

#include <QWidget> //bibliothèque Qt

class MainWindow : public QWidget { //dérive de QWidget


Q_OBJECT //détail technique Qt
public:
MainWindow(QWidget *parent = nullptr); //constructeur
~MainWindow(); //destructeur si besoin
};

7. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


mainwindow.cpp :

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
QWidget{parent} //initialiser fenêtre principale
// + autres initialisations propres
{
//initialiser les données propres à l’application
//créer les composants qui s’ajoutent dans la fenêtre
//faire les connexions entre événements et méthodes de rappel
}

– Pour une fenêtre avec barre de menu et de statut et composants encas-


trables : hériter de QMainWindow

8. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.4 Compilation manuelle
– Créer un fichier qmake pour le projet, p.ex. monprojet.pro, dans lequel

– indiquer les modules de Qt utilisés : QT += core gui


– et greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
– configurer le compilateur : CONFIG += c++14
– ajouter les fichiers en-tête : ajouter HEADER += fichier.h pour
chaque fichier en-tête
– ajouter les fichiers sources : ajouter SOURCES += fichier.cpp pour
chaque fichier source
– indiquer éventuellement le nom de l’exécutable TARGET = helloworld

– Créer le Makefile : qmake monprojet.pro -o Makefile


– Lancer la compilation : make
– Exécuter : helloworld.exe sous windows, ./helloworld sous unix

9. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.5 Utiliser QtCreator
– Pour aider à la création de ces fichiers : créer un projet avec QtCreator

→ Nouveau Projet
→ Application Qt avec Widgets
→ Donner le nom du projet
→ Choisir le Kit (Desktop Qt 5.x.x MinGW 32 bit p.ex.)
→ Information sur la classe : choisir le nom de la classe (MainWindow par
défaut, choisir un nom plus parlant), les noms des fichiers contenant
cette classe et décocher Générer l’interface graphique
→ Gestion du projet (ne rien faire ici)

10. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.6 Exemple simple en Qt
Affichage d’une fenêtre vide avec un titre : fenêtre principale FenetreVide

main.cpp :

#include <QApplication> //bibliothèque Qt


#include "fenetrevide.h"

int main(int argc, char *argv[])


{
QApplication a{argc, argv};
FenetreVide w;
w.show();

return a.exec();
}

11. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


Fenêtre vide FenetreVide : fenêtre vide avec un titre
fenetrevide.h :

#include <QWidget> //bibliothèque Qt

class FenetreVide : public QWidget {


Q_OBJECT
public:
FenetreVide(QWidget *parent = nullptr);
};

fenetrevide.cpp :

FenetreVide::FenetreVide(QWidget *parent) : QWidget{parent}


{
resize(200, 100); //taille
setMinimumSize(100,80); //taille minimum
setMaximumSize(300,300); //taille maximum
setWindowTitle("Fenêtre vide"); //titre
}

12. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


Résultat :
windows Linux

13. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.7 Ajout de composants
– On ajoute un composant dans une fenêtre en le créant avec new
(en général dans le constructeur de la fenêtre principale)
– On doit lui passer sa fenêtre parent dans le constructeur
– Si besoin d’accéder plus tard directement à ce composant : garder en mé-
moire un pointeur dessus
– Pour fermer (si nécessaire) la fenêtre ou un composant : appeler dessus la
méthode close()
– Les composants seront détruits automatiquement avec delete par leur
parent quand il sera lui-même détruit

14. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


#include<QPushButton> //bibliothèque Qt pour le bouton

MainWindow::MainWindow(QWidget *parent) : QWidget{parent}


{
resize(320, 240);
setMinimumSize(100,100);
setMaximumSize(400,400);
setWindowTitle("Fenêtre avec bouton");
auto b = new QPushButton{"Bouton", this}; //ajout bouton
b->setGeometry(20, 10, 100, 50); //géométrie bouton
}

– Mais pour l’instant, le bouton ne fait rien

15. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.8 Gestion des événements
– La boucle événementielle de l’application :

– retire les événements bas niveaux de la file du système


– les transforme en événements haut niveau de la boîte à outils
– cherche en réponse à l’événement à faire réagir le bon composant en
appelant dessus la bonne méthode de rappel

– Pour cela elle signale l’événement :

– au composant à l’origine de l’événement qui réagit en appelant la fonc-


tion de rappel qu’on lui a donnée au préalable (GTK+)
– au composant à l’origine de l’événement qui cherche à réagir en cher-
chant la fonction de rappel enregistrée correspondante, et sinon trans-
met l’événement au composant qui le contient (wxWidgets)
– à l’application qui cherche le composant et la méthode à appeler dans
une table événementielle globale (Qt)

16. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.9 Fonctions de rappel
– L’application réagit à un événement en appelant une fonction de rappel
(gestionnaire d’événement) :

– une fonction/méthode qui prend l’événement en paramètre


– qui peut interroger l’événement pour en savoir plus sur la situation

– On enregistre auprès des composants des fonctions de rappels par rapport


à certains événements
– Lorsque l’application demande au composant de réagir à un événement :

– le composant cherche s’il y a une fonction de rappel enregistrée pour


ce type d’événement
– et si oui appelle cette fonction en lui passant l’événement en paramètre

17. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.10 Qt : signaux, slots et table événementielle globale
– Qt ajoute une couche de communication entre objets
– Une classe peut avoir des méthodes signal :

– des méthodes identifiées comme signal


– dont la définition (le code) sera générée automatiquement par Qt

– Une classe peut avoir des méthodes réceptrices (slot) :

– des méthodes normales identifiées comme réceptrices (slot)


– ces méthodes peuvent aussi être appelées normalement

– Qt a une table événementielle globale dans laquelle on connecte

– un composant émetteur et un de ses signaux


– à un composant récepteur et une de ses méthodes réceptrices

18. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


– Quand un objet veut se signaler aux autres il émet un signal avec des
valeurs :

– il appelle d’une façon spéciale une de ses méthodes signal avec des
valeurs en paramètres : des valeurs émises

– Qt cherche dans sa table les entrées (objet+méthode réceptrices) corres-


pondant à l’objet émetteur et au signal émis
– Et appelle les méthodes réceptrices sur les objets récepteurs des entrées
trouvées en leur passant en paramètres les valeurs émises du signal

19. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.10.1 Signal
– Un signal est une méthode déclarée dans signals:
class Valeur : public QObject { Q_OBJECT
int d_valeur;
public:
Valeur(int v);
void changeValeur(int v);
signals: //méthodes signal, spécifique Qt
void valeurChangee(int valeur);
};

– Le code de cette méthode ne doit pas être écrit


– Un signal est émis en appelant avec emit la méthode avec des valeurs :
void Valeur::changeValeur(int v) {
d_valeur = v;
emit valeurChangee(d_valeur); //émet le signal, spécifique Qt
}

20. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.10.2 Méthode réceptrices
– Une méthode réceptrice est une méthode normale déclarée dans slots:
class Afficheur : public QObject { Q_OBJECT
public slots: //méthodes réceptrices, spécifique Qt
void afficheValeur(int v);
};

void Afficheur::afficheValeur(int v) {
QTextStream stream{stdout};
stream<<"valeur reçue "<<v;
}

– On peut appeler directement cette méthode :


Afficheur aff{};
aff.afficheValeur(10);

– Elle peut être appelée indirectement en connectant l’objet et sa méthode


réceptrice à un objet émetteur et un signal

21. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


2.10.3 Connexion entre signal et méthode réceptrice
– Pour que

– quand l’objet objemetteur de classe Emetteur émet le signal signalEmis,


– soit appelée sur l’objet objrecepteur de classe Recepteur la mé-
thode réceptrice traiteSignal avec les valeurs du signal en para-
mètre

– Faire la connexion dans la table globale de Qt avec connect :

//les objets et les méthodes doivent être passés par adresse


connect(&objemetteur, &Emetteur::signalEmis,
&objrecepteur, &Recepteur::Traitesignal);

– La méthode signal et la méthode réceptrice connectées doivent avoir la


même signature

22. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


Valeur v{10};
Afficheur aff{};
connect(&v, &Valeur::valeurChangee, &aff, &Afficheur::afficheValeur);
v.changeValeur(20);
//v émet le signal valeurChangee(20)
//Qt appelle alors aff.afficheValeur(20)

– Une classe émettrice ou réceptrice doit hériter de QObject (où une de ses
classes dérivées) et contenir Q_OBJECT au début de sa déclaration
– Plusieurs signaux peuvent être connectés à une même méthode réceptrice
– Un signal peut être connecté à plusieurs méthodes réceptrices
– Un signal peut être connecté à un autre signal : quand le premier sera
émis, le deuxième le sera avec les mêmes valeurs
– Connaître l’objet émetteur dans une méthode réceptrice : QObject::sender()

23. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


– Exemple : fenêtre avec deux boutons, un pour afficher des informations,
un pour quitter

mainwindow.h :

#include<QWidget>

class MainWindow : public QWidget {


Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
private slots: //méthodes réceptrices de rappel
void onAbout(); //pour le bouton about
void onQuit(); //pour le bouton quitter
};

24. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


– Un bouton QPushButton émet le signal clicked() quand on le clique

mainwindow.cpp

#include "mainwindow.h"
#include<QPushButton>
#include<QMessageBox>

MainWindow::MainWindow(QWidget *parent) : QWidget{parent}


{
resize(320, 240);
setWindowTitle("Fenêtre avec boutons");
auto babout = new QPushButton{"About", this};
babout->move(20,10);
auto bquit = new QPushButton{"Quitter", this};
bquit->move(140,10);
connect(babout, &QPushButton::clicked, this, &MainWindow::onAbout);
connect(bquit, &QPushButton::clicked, this, &MainWindow::onQuit);
}

25. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


//quand bouton quitter est pressé
void MainWindow::onQuit()
{
close();
}

//quand bouton About est pressé


void MainWindow::onAbout()
{
QMessageBox msgBox{QMessageBox::Information,
"Information", "Bouton About cliqué"};
msgBox.exec();
}

26. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


3 Quelques utilitaires de Qt
3.1 Chaînes de caractères
– Classes pour éviter les problèmes entre différents encodages de caractères :
– Caractère : classe QChar (méthodes qui testent le type du caractère)
– Chaîne de caractères : classe QString
– Créer à partir d’une chaîne C++ str (de type std::string) :
fonction statique QString::fromStdString(str)
– QString possède les méthodes des chaînes de la bibliothèque standard
C++ plus ses propres méthodes
– Convertir en nombre :

– méthodes toDouble(bool* ok) et ToInt(bool* ok) : si erreur


mettent ok à faux et renvoient 0.0 et 0

27. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


– Convertir un nombre en chaîne :

– QString::number(int val) : renvoie la chaîne correspondant à


l’entier
– QString::number(double n, char format=’g’,
int precision=6) : renvoie la chaîne correspondant au réel
(format = ’e’, ’f’ ou ’g’)

– Écrire dans une chaîne txt comme dans un flot :

– créer un flot associé à la chaîne : QTextStream{&txt}


– écrire dans le flot comme d’habitude avec <<

QString txt;
QTextStream{&txt} << "pi = " << 3.14;

28. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


3.2 Classes utiles pour taille et position
– Indiquer une position : classe QPoint

class QPoint ... {


public:
QPoint()
QPoint(int x, int y);
int x() const;
int y() const;
void setX(int x);
void setY(int y);
// et opérateurs + et - avec QPoint et QSize
};

– Indiquer une taille : classe QSize

class QSize ... {


public:
QSize();
QSize(int w, int ht);
int height() const;
int witdh() const;
void setHeight(int h);
void setWidth(int w);
//et opérateurs + et -,
//et opérateurs * et / avec coefficient
};

29. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


3.3 Premiers composants
– Bouton : classe QPushButton

class QPushButton ... {


public:
QPushButton(QWidget *parent = Q_NULLPTR);
QPushButton(const QString &text, QWidget *parent = Q_NULLPTR);
void setText(const QString &text); //étiquette du bouton
QString text() const;
void move(int x, int y);
void setGeometry(int x, int y, int w, int h);
};

– Émet le signal clicked() quand il est cliqué


– Raccourci clavier : précéder le caractère de & ("&Download" → ALT+D)

30. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière


– Dialogue affichant un message : classe QMessageBox

class QMessageBox ... {


public:
QMessageBox();
QMessageBox(Icon icon, const QString &title,
const QString &text,
StandardButtons buttons = NoButton);
void setIcon(Icon);
void setWindowTitle(const QString &title);
void setText(const QString &text);
void setStandardButtons(StandardButtons buttons);
int exec(); //renvoie bouton cliqué
};

– Les valeurs données doivent être préfixées par


QMessageBox::
– Icône : NoIcon, Question, Information, Warning,
Critical
– Boutons : combinaison avec | de : Ok, Open, Save,
Cancel, Close, Discard, Apply, Reset, Yes,
No, Abort . . .
– On lance le dialogue avec exec() qui renvoie la
valeur du bouton cliqué par l’utilisateur pour fer-
mer le dialogue

31. Prog événementielle et interfaces graphiques – L2 INFO Stéphane Rivière

Vous aimerez peut-être aussi