CPP - zz3 05 QT
CPP - zz3 05 QT
CPP - zz3 05 QT
Interfaces graphiques
avec Qt
Luc Touraille
Christophe Duhamel
Bruno Bachelet
Actuellement
C++ : Qt, GTK+
Java : Swing
C# : composants .net
C : X11, GTK, TCL/TK
Méthodes et outils de développement logiciel - ISIMA / ZZ3 - 2011-2012 139
Interfaces graphiques objets (1/2)
Ensemble de composants graphiques
Appelés aussi «widgets»
Bibliothèque ⇒ widgets de base
Un type de widget = une classe
Réutilisation
Par héritage: extension d'un type de widget
Par composition: assemblage de widgets
Type de composants
Widgets de haut niveau
Fenêtre, boîte de dialogue…
Widgets de bas niveau
Bouton, label, zone de texte, case à cocher, bouton radio…
Composants invisibles
Actions, événements (e.g. clic de souris), conteneur…
Méthodes et outils de développement logiciel - ISIMA / ZZ3 - 2011-2012 140
Interfaces graphiques objets (2/2)
Interaction entre les composants
Inhérent à tout système objet
Mécanisme classique des messages
Mécanisme de message basé sur les événements
Un objet subit un événement ⇒ répercussion sur d'autres
#ifndef NUMBERDISPLAY_HPP
#define NUMBERDISPLAY_HPP
#include <QtGui/QWidget>
#endif // NUMBERDISPLAY_HPP
NumberDisplay::NumberDisplay(QWidget *parent)
: QWidget(parent)
{
QLCDNumber * number = new QLCDNumber;
QSlider * slider = new QSlider(Qt::Horizontal);
QVBoxLayout * mainLayout = new QVBoxLayout;
mainLayout->addWidget(number);
mainLayout->addWidget(slider);
setLayout(mainLayout);
connect(slider, SIGNAL(valueChanged(int)),
number, SLOT(display(int)));
}
Méthodes et outils de développement logiciel - ISIMA / ZZ3 - 2011-2012 144
Exemple simple en Qt (4/7)
Création de deux widgets
La barre QSlider
L'affichage LCD QLCDNumber
Mécanisme de messages
Méthode connect() relie deux méthodes
Signal: méthode déclencheuse
Slot: méthode déclenchée
Deux macros SIGNAL et SLOT
Lorsque slider.valueChanged(int) déclenchée
⇒ number.display(int) exécutée
Méthodes et outils de développement logiciel - ISIMA / ZZ3 - 2011-2012 145
Exemple simple en Qt (5/7)
Fichier «main.cpp»
#include <QtGui/QApplication>
#include "NumberDisplay.hpp"
NumberDisplay w;
w.show();
Pré-construction : qmake
Génération d'un makefile spécifique à l'environnement,
avec les paramètres du fichier projet
Support de plusieurs compilateurs
Construction : make
Invocation de qmake si fichier projet modifié
Appel du préprocesseur moc
Création du fichier «moc_NumberDisplay.cpp»
Compilation du projet
Arborescence d'objets
Un QObject peut avoir un parent et des enfants (QObjects)
Un parent "possède" ses enfants : il les détruit quand il est détruit
⇒ Allocation dynamique des objets (sauf éventuellement les racines)
Affectation du parent
À la construction
Lors de l'ajout à un conteneur
mainWidget
imageArea sizeComboBox
imageLabel
QWidget mainWidget;
mainWidget.setLayout(layout);
// mainWidget parent de imageArea et de sizeComboBox
mainWidget.show();
return a.exec();
// destruction de mainWidget
// ⇒ destruction de sizeComboBox
// ⇒ destruction de imageArea
// ⇒ destruction de imageLabel
}
#include <QtCore/QObject>
Compteur::Compteur(int valeurInitiale)
: valeur_(valeurInitiale)
{}
void Compteur::incrementer()
{
++valeur_;
emit valeurIncrementee(valeur_);
}
Méthodes et outils de développement logiciel - ISIMA / ZZ3 - 2011-2012 156
Signaux et slots (4/5)
Exemple «Valeur.hpp»
Valeur::Valeur()
: valeur_(0)
{}
#include <QtCore/QCoreApplication>
#include "Compteur.hpp"
#include "Recepteur.hpp"
#include "Valeur.hpp"
Recepteur r;
Compteur c(10);
Valeur v;
QObject::connect(&c, SIGNAL(valeurIncrementee(int)),
&r, SLOT(recevoir(int)));
QObject::connect(&v, SIGNAL(valeurModifiee(int)),
&r, SLOT(recevoir(int)));
Composant Evénement e
Enregistrement
Ecouteur 2 Objet o
Appel méthode e(o)
MouseAdapter
«implémente»
+ mouseClicked(:MouseEvent)
+ mouseEntered(:MouseEvent)
Méthodes vides + mouseExited(:MouseEvent)
+ mousePressed(:MouseEvent)
+ mouseReleased(:MouseEvent)
MonEcouteur1
+ mouseClicked(:MouseEvent)
+ mouseEntered(:MouseEvent)
+ mouseExited(:MouseEvent) MonEcouteur2
+ mousePressed(:MouseEvent)
+ mouseReleased(:MouseEvent) + mousePressed(:MouseEvent)
Obligation de surcharger Seules les méthodes nécessaires
toutes les méthodes sont surchargées
Consulter
Modifier
Exemple d'introspection
o->setProperty("couleur", "Rouge");
QMetaEnum couleurEnum =
ZoneDeTexte::staticMetaObject.enumerator(0);
cout << couleurEnum.valueToKey(z.couleur());
Objectif
Gestionnaires de
placement pour le reste
Fichier «SelecteurDeNombre.hpp»
#include <QtGui/QLCDNumber>
#include <QtGui/QSlider>
private:
QLCDNumber * nombre_;
QSlider * ascenseur_;
};
SelecteurDeNombre::SelecteurDeNombre(QWidget *parent)
: QWidget(parent)
{
nombre_ = new QLCDNumber;
ascenseur_ = new QSlider(Qt::Horizontal);
QVBoxLayout * layout = new QVBoxLayout;
layout->addWidget(nombre_);
layout->addWidget(ascenseur_);
setLayout(layout);
connect(ascenseur_, SIGNAL(valueChanged(int)),
nombre_, SLOT(display(int)));
}
private slots:
void ajouterNombre();
void retirerNombre();
private:
QListWidget * liste_;
SelecteurDeNombre * selecteur_;
};
connect(boutonAjouter, SIGNAL(clicked()),
this, SLOT(ajouterNombre()));
connect(boutonRetirer, SIGNAL(clicked()),
this, SLOT(retirerNombre()));
}
void ManagerDeNombre::ajouterNombre() {
liste_->addItem(
QString::number(selecteur_->nombreCourant()));
}
void ManagerDeNombre::retirerNombre() {
delete liste_->takeItem(liste_->currentRow());
}
Méthodes et outils de développement logiciel - ISIMA / ZZ3 - 2011-2012 172
Placement des widgets (1/2)
Grille : QGridLayout
Formulaire : QFormLayout
Exemples
QGroupBox
QTabWidget
Exemple
private:
void creerActions();
void creerMenus();
ManagerDeNombre * manager_;
QAction * exitAction_;
QAction * resetAction_;
};
MainWindow::MainWindow(QWidget * parent)
: QMainWindow(parent)
{
manager_ = new ManagerDeNombre;
setCentralWidget(manager_);
createActions();
createMenus();
}
void MainWindow::createActions()
{
exitAction_ = new QAction("&Quitter", this);
exitAction_->setShortcut(QKeySequence::Close);
connect(exitAction_, SIGNAL(triggered()),
this, SLOT(close()));
connect(resetAction_, SIGNAL(triggered()),
manager_, SLOT(reset()));
}
void MainWindow::createMenus()
{
QMenu * fileMenu = menuBar()->addMenu("&Fichier");
fileMenu->addAction(exitAction_);
Objectif
Séparer la présentation (vue) des donnés (modèle)
Couplage faible réalisé par un intermédiaire
Le contrôleur
Il assure la cohérence entre les deux couches
Méthodes et outils de développement logiciel - ISIMA / ZZ3 - 2011-2012 182
MVC : le modèle
< état
Conclusion
Maintenance facilitée par le découplage vue(s)-modèle
Utilisation des patrons Observateur, Médiateur et Stratégie
Utilisé principalement pour les interfaces graphiques
Sous forme simplifiée dans Qt et Swing
Variantes possibles
Contrôleur enlevé
Mécanisme supplémentaire: l'inversion de contrôle
Méthodes et outils de développement logiciel - ISIMA / ZZ3 - 2011-2012 186
Qt : architecture Modèle-Vue (1/2)
⇒ Grande réutilisabilité
Méthodes et outils de développement logiciel - ISIMA / ZZ3 - 2011-2012 187
Qt : architecture Modèle-Vue (2/2)
Utilisation de délégués pour le rendu et l'édition
des données à l'intérieur des vues
Trois types
Données séquentielles (liste)
Données tabulaire
Données arborescentes
Le plus générique : les deux autres sont des cas particuliers
XML
Programmation concurrente