Vous êtes sur la page 1sur 30

2

Crer des botes de dialogue


Au sommaire de ce chapitre Drivation de QDialog Description dtaille des signaux et slots Conception rapide dune bote de dialogue Botes de dialogue multiformes Botes de dialogue dynamiques Classes de widgets et de botes de dialogue intgres

Dans ce chapitre, vous allez apprendre crer des botes de dialogue laide de Qt. Celles-ci prsentent diverses options et possibilits aux utilisateurs et leur permettent de dnir les valeurs des options et de faire des choix. On les appelle des botes de dialogue, puisquelles donnent la possibilit aux utilisateurs et aux applications de "discuter". La majorit des applications GUI consiste en une fentre principale quipe dune barre de menus et doutils, laquelle on ajoute des douzaines de botes de dialogue. Il est galement possible de crer des applications "bote de dialogue" qui rpondent directement aux choix de lutilisateur en accomplissant les actions appropries (par exemple, une application de calculatrice).

16

Qt4 et C++ : Programmation dinterfaces GUI

Nous allons crer notre premire bote de dialogue en crivant compltement le code pour vous en expliquer le fonctionnement. Puis nous verrons comment concevoir des botes de dialogue grce au Qt Designer, un outil de conception de Qt. Avec le Qt Designer, vous codez beaucoup plus rapidement et il est plus facile de tester les diffrentes conceptions et de les modier par la suite.

Drivation de QDialog
Notre premier exemple est une bote de dialogue Find crite totalement en langage C++ (voir Figure 2.1). Nous limplmenterons comme une classe part entire. Ainsi, elle deviendra un composant indpendant et autonome, comportant ses propres signaux et slots.
Figure 2.1 La bote de dialogue Find

Le code source est rparti entre deux chiers : finddialog.h et finddialog.cpp. Nous commencerons par finddialog.h.
1 2 3 4 5 6 7

#ifndef FINDDIALOG_H #define FINDDIALOG_H #include <QDialog> class class class class QCheckBox; QLabel; QLineEdit; QPushButton;

Les lignes 1 et 2 (et 27) protgent le chier den-tte contre les inclusions multiples. La ligne 3 contient la dnition de QDialog, la classe de base pour les botes de dialogue dans Qt. QDialog hrite de QWidget. Les lignes 4 7 sont des dclarations pralables des classes Qt que nous utiliserons pour implmenter la bote de dialogue. Une dclaration pralable informe le compilateur C++ quune classe existe, sans donner tous les dtails dune dnition de classe (gnralement situe dans un chier den-tte). Nous en parlerons davantage dans un instant. Nous dnissons ensuite FindDialog comme une sous-classe de QDialog:
8 9 10

class FindDialog: public QDialog { Q_OBJECT

Chapitre 2

Crer des botes de dialogue

17

11 12

public: FindDialog(QWidget *parent = 0);

La macro Q_OBJECT au dbut de la dnition de classe est ncessaire pour toutes les classes qui dnissent des signaux ou des slots. Le constructeur de FindDialog est typique des classes Qt de widgets. Le paramtre parent spcie le widget parent. Par dfaut, cest un pointeur nul, ce qui signie que la bote de dialogue na pas de parent.
13 14 15

signals: void findNext(const QString &str, Qt::CaseSensitivity cs); void findPrevious(const QString &str, Qt::CaseSensitivity cs);

La section des signaux dclare deux signaux que la bote de dialogue met quand lutilisateur clique sur le bouton Find. Si loption Search backward est active, la bote de dialogue met findPrevious(); sinon elle met findNext(). Le mot-cl signals est en fait une macro. Le prprocesseur C++ la convertit en langage C++ standard avant que le compilateur ne la voie. Qt::CaseSensitivity est un type numration qui peut prendre les valeurs Qt::CaseSensitive et Qt::CaseInsensitive.
16 17 18 19 20 21 22 23 24 25 26 27

private slots: void findClicked(); void enableFindButton(const QString &text); private: QLabel *label; QLineEdit *lineEdit; QCheckBox *caseCheckBox; QCheckBox *backwardCheckBox; QPushButton *findButton; QPushButton *closeButton; }; #endif

Dans la section prive de la classe, nous dclarons deux slots. Pour implmenter les slots, vous devez avoir accs la plupart des widgets enfants de la bote de dialogue, nous conservons donc galement des pointeurs vers eux. Le mot-cl slots, comme signals, est une macro qui se dveloppe pour produire du code que le compilateur C++ peut digrer. Sagissant des variables prives, nous avons utilis les dclarations pralables de leurs classes. Ctait possible puisque ce sont toutes des pointeurs et que nous ny accdons pas dans le chier den-tte, le compilateur na donc pas besoin des dnitions de classe compltes. Nous aurions pu inclure les chiers den-tte importants (<QCheckBox>, <QLabel>, etc.), mais la compilation se rvle plus rapide si vous utilisez les dclarations pralables ds que possible.

18

Qt4 et C++ : Programmation dinterfaces GUI

Nous allons dsormais nous pencher sur finddialog.cpp qui contient limplmentation de la classe FindDialog.
1 2

#include <QtGui> #include "finddialog.h"

Nous incluons dabord <QtGui>, un chier den-tte qui contient la dnition des classes GUI de Qt. Qt est constitu de plusieurs modules, chacun deux se trouvant dans sa propre bibliothque. Les modules les plus importants sont QtCore, QtGui, QtNetwork, QtOpenGL, QtSql, QtSvg et QtXml. Le chier den-tte <QtGui> renferme la dnition de toutes les classes qui font partie des mo dules QtCore et QtGui. En incluant cet en-tte, vous vitez la tche fastidieuse dinclure chaque classe sparment. Dans filedialog.h, au lieu dinclure <QDialog> et dutiliser des dclarations pralables pour QCheckBox, QLabel, QLineEdit et QPushButton, nous aurions simplement pu spcier <QtGui>. Toutefois, il est gnralement malvenu dinclure un chier den-tte si grand depuis un autre chier den-tte, notamment dans des applications plus importantes.
3 4 5 6 7 8 9 10 11 12 13

FindDialog::FindDialog(QWidget *parent) : QDialog(parent) { label = new QLabel(tr("Find &what:")); lineEdit = new QLineEdit; label->setBuddy(lineEdit); caseCheckBox = new QCheckBox(tr("Match &case")); backwardCheckBox = new QCheckBox(tr("Search &backward")); findButton = new QPushButton(tr("&Find")); findButton->setDefault(true); findButton->setEnabled(false); closeButton = new QPushButton(tr("Close"));

14

A la ligne 4, nous transmettons le paramtre parent au constructeur de la classe de base. Puis nous crons les widgets enfants. Les appels de la fonction tr() autour des littraux chane les marquent dans loptique dune traduction en dautres langues. La fonction est dclare dans QObject et chaque sous-classe qui contient la macro Q_OBJECT. Il est recommand de prendre lhabitude dencadrer les chanes visibles par lutilisateur avec tr(), mme si vous navez pas lintention de faire traduire vos applications en dautres langues dans limmdiat. La traduction des applications Qt est aborde au Chapitre 17. Dans les littraux chane, nous utilisons le caractre & pour indiquer des raccourcis clavier. Par exemple, la ligne 11 cre un bouton Find que lutilisateur peut activer en appuyant sur Alt+F sur les plates-formes qui prennent en charge les raccourcis clavier. Le caractre & peut galement tre employ pour contrler le focus, cest--dire llment actif : la ligne 6, nous crons une tiquette avec un raccourci clavier (Alt+W), et la ligne 8, nous dnissons lditeur de lignes comme widget compagnon de ltiquette. Ce compagnon (buddy) est un widget

Chapitre 2

Crer des botes de dialogue

19

qui reoit le focus quand vous appuyez sur le raccourci clavier de ltiquette. Donc, quand lutilisateur appuie sur Alt+W (le raccourci de ltiquette), lditeur de lignes reoit le contrle. A la ligne 12, nous faisons du bouton Find le bouton par dfaut de la bote de dialogue en appelant setDefault(true). Le bouton par dfaut est le bouton qui est press quand lutilisateur appuie sur Entre. A la ligne 13, nous dsactivons le bouton Find. Quand un widget est dsactiv, il apparat gnralement gris et ne rpondra pas en cas dinteraction de lutilisateur.
15 16 17 18 19 20 connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(enableFindButton(const QString &))); connect(findButton, SIGNAL(clicked()), this, SLOT(findClicked())); connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));

Le slot priv enableFindButton(const QString &) est appel ds que le texte change dans lditeur de lignes. Le slot priv findClicked() est invoqu lorsque lutilisateur clique sur le bouton Find. La bote de dialogue se ferme si lutilisateur clique sur Close. Le slot close() est hrit de QWidget et son comportement par dfaut consiste masquer le widget (sans le supprimer). Nous allons tudier le code des slots enableFindButton() et findClicked() ultrieurement. Etant donn que QObject est lun des anctres de FindDialog, nous pouvons omettre le prxe QObject:: avant les appels de connect().
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

QHBoxLayout *topLeftLayout = new QHBoxLayout; topLeftLayout->addWidget(label); topLeftLayout->addWidget(lineEdit); QVBoxLayout *leftLayout = new QVBoxLayout; leftLayout->addLayout(topLeftLayout); leftLayout->addWidget(caseCheckBox); leftLayout->addWidget(backwardCheckBox); QVBoxLayout *rightLayout = new QVBoxLayout; rightLayout->addWidget(findButton); rightLayout->addWidget(closeButton); rightLayout->addStretch(); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addLayout(leftLayout); mainLayout->addLayout(rightLayout); setLayout(mainLayout);

Nous disposons ensuite les widgets enfants laide des gestionnaires de disposition. Les dispositions peuvent contenir des widgets et dautres dispositions. En imbriquant QHBoxLayout, QVBoxLayout et QGridLayout dans diverses combinaisons, il est possible de concevoir des botes de dialogue trs sophistiques.

20

Qt4 et C++ : Programmation dinterfaces GUI

Figure 2.2 Les dispositions de la bote de dialogue Find


leftLayout topLeftLayout

Titre de la fentre

QLabel

QLineEdit

QPushButton QPushButton

rightLayout rightLayout

QCheckBox QCheckBox

Elment d'espacement

Pour la bote de dialogue Find, nous employons deux QHBoxLayout et deux QVBoxLayout, comme illustr en Figure 2.2. La disposition externe correspond la disposition principale ; elle est installe sur FindDialog la ligne 35 et est responsable de toute la zone de la bote de dialogue. Les trois autres dispositions sont des sous-dispositions. Le petit "ressort" en bas droite de la Figure 2.2 est un lment despacement (ou "tirement"). Il comble lespace vide sous les boutons Find et Close, ces boutons sont donc srs de se trouver en haut de leur disposition. Les gestionnaires de disposition prsentent une subtilit : ce ne sont pas des widgets. Ils hritent de QLayout, qui hrite son tour de QObject. Dans la gure, les widgets sont reprsents par des cadres aux traits pleins et les dispositions sont illustres par des cadres en pointills pour mettre en avant la diffrence qui existe entre eux. Dans une application en excution, les dispositions sont invisibles. Quand les sous-dispositions sont ajoutes la disposition parent (lignes 25, 33 et 34), les sousdispositions sont automatiquement reparentes. Puis, lorsque la disposition principale est installe dans la bote de dialogue (ligne 35), elle devient un enfant de cette dernire et tous les widgets dans les dispositions sont reparents pour devenir des enfants de la bote de dialogue. La hirarchie parent-enfant ainsi obtenue est prsente en Figure 2.3.
36 37 38

setWindowTitle(tr("Find")); setFixedHeight(sizeHint().height()); }
FindDialog QLabel (label) QLineEdit (lineEdit) QCheckBox (caseCheckBox) QCheckBox (backwardCheckBox) QPushButton (ndButton) QPushButton (closeButton) QHBoxLayout (mainLayout) QVBoxLayout (leftLayout) QHBoxLayout (topLeftLayout) QVBoxLayout (rightLayout)

Figure 2.3 Les relations parentenfant de la bote de dialogue Find

Enn, nous dnissons le titre afcher dans la barre de titre de la bote de dialogue et nous congurons la fentre pour quelle prsente une hauteur xe, tant donn quelle ne contient

Chapitre 2

Crer des botes de dialogue

21

aucun widget qui peut occuper de lespace supplmentaire verticalement. La fonction QWidget::sizeHint() retourne la taille "idale" dun widget. Ceci termine lanalyse du constructeur de FindDialog. Vu que nous avons cr les widgets et les dispositions de la bote de dialogue avec new, il semblerait logique dcrire un destructeur qui appelle delete sur chaque widget et disposition que nous avons crs. Toutefois, ce nest pas ncessaire, puisque Qt supprime automatiquement les objets enfants quand le parent est dtruit, et les dispositions et widgets enfants sont tous des descendants de FindDialog. Nous allons prsent analyser les slots de la bote de dialogue :
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54

void FindDialog::findClicked() { QString text = lineEdit->text(); Qt::CaseSensitivity cs = caseCheckBox->isChecked()? Qt::CaseSensitive : Qt::CaseInsensitive; if (backwardCheckBox->isChecked()) { emit findPrevious(text, cs); } else { emit findNext(text, cs); } } void FindDialog::enableFindButton(const QString &text) { findButton->setEnabled(!text.isEmpty()); }

Le slot findClicked() est appel lorsque lutilisateur clique sur le bouton Find. Il met le signal findPrevious() ou findNext(), en fonction de loption Search backward. Le motcl emit est spcique Qt ; comme les autres extensions Qt, il est converti en langage C++ standard par le prprocesseur C++. Le slot enableFindButton() est invoqu ds que lutilisateur modie le texte dans lditeur de lignes. Il active le bouton sil y a du texte dans cet diteur, sinon il le dsactive. Ces deux slots compltent la bote de dialogue. Nous avons dsormais la possibilit de crer un chier main.cpp pour tester notre widget FindDialog:
1 2 3 4 5 6 7 8 9

#include <QApplication> #include "finddialog.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); FindDialog *dialog = new FindDialog; dialog->show(); return app.exec(); }

Pour compiler le programme, excutez qmake comme dhabitude. Vu que la dnition de la classe FindDialog comporte la macro Q_OBJECT, le chier Makele gnr par qmake

22

Qt4 et C++ : Programmation dinterfaces GUI

contiendra des rgles particulires pour excuter moc, le compilateur de mta-objets de Qt. (Le systme de mta-objets de Qt est abord dans la prochaine section.) Pour que moc fonctionne correctement, vous devez placer la dnition de classe dans un chier den-tte, spar du chier dimplmentation. Le code gnr par moc inclut ce chier dentte et ajoute une certaine "magie" C++.

moc doit tre excut sur les classes qui se servent de la macro Q_OBJECT. Ce nest pas un problme parce que qmake ajoute automatiquement les rgles ncessaires dans le chier Makele. Toutefois, si vous oubliez de gnrer nouveau votre chier Makele laide de qmake et que moc nest pas excut, lditeur de liens indiquera que certaines fonctions sont dclares mais pas implmentes. Les messages peuvent tre plutt obscurs. GCC produit des avertissements comme celui-ci :
finddialog.o: In function FindDialog::tr(char const*, char const*): /usr/lib/qt/src/corelib/global/qglobal.h:1430: undefined reference to FindDialog::staticMetaObject

La sortie de Visual C++ commence ainsi :


finddialog.obj: error LNK2001: unresolved external symbol "public:~virtual int __thiscall MyClass::qt_metacall(enum QMetaObject ::Call,int,void * *)"

Si vous vous trouvez dans ce cas, excutez nouveau qmake pour mettre jour le chier Makele, puis gnrez nouveau lapplication. Excutez maintenant le programme. Si des raccourcis clavier apparaissent sur votre plateforme, vriez que les raccourcis Alt+W, Alt+C, Alt+B et Alt+F dclenchent le bon comportement. Appuyez sur la touche de tabulation pour parcourir les widgets en utilisant le clavier. Lordre de tabulation par dfaut est lordre dans lequel les widgets ont t crs. Vous pouvez le modier grce QWidget::setTabOrder(). Proposer un ordre de tabulation et des raccourcis clavier cohrents permet aux utilisateurs qui ne veulent pas (ou ne peuvent pas) utiliser une souris de proter pleinement de lapplication. Les dactylos apprcieront galement de pouvoir tout contrler depuis le clavier. Dans le Chapitre 3, nous utiliserons la bote de dialogue Find dans une application relle, et nous connecterons les signaux findPrevious() et findNext() certains slots.

Description dtaille des signaux et slots


Le mcanisme des signaux et des slots est une notion fondamentale en programmation Qt. Il permet au programmeur de lapplication de relier des objets sans que ces objets ne sachent quoi que ce soit les uns sur les autres. Nous avons dj connect certains signaux et slots ensemble, dclar nos propres signaux et slots, implment nos slots et mis nos signaux. Etudions dsormais ce mcanisme plus en dtail.

Chapitre 2

Crer des botes de dialogue

23

Les slots sont presque identiques aux fonctions membres ordinaires de C++. Ils peuvent tre virtuels, surchargs, publics, protgs ou privs, tre invoqus directement comme toute autre fonction membre C++, et leurs paramtres peuvent tre de nimporte quel type. La diffrence est quun slot peut aussi tre connect un signal, auquel cas il est automatiquement appel chaque fois que le signal est mis. Voici la syntaxe de linstruction connect():
connect(sender, SIGNAL(signal), receiver, SLOT(slot));

o sender et receiver sont des pointeurs vers QObject et o signal et slot sont des signatures de fonction sans les noms de paramtre. Les macros SIGNAL() et SLOT() convertissent leur argument en chane. Dans les exemples tudis jusque l, nous avons toujours connect les signaux aux divers slots. Il existe dautres possibilits envisager.

Un signal peut tre connect plusieurs slots :


connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int))); connect(slider, SIGNAL(valueChanged(int)), this, SLOT(updateStatusBarIndicator(int)));

Quand le signal est mis, les slots sont appels les uns aprs les autres, dans un ordre non spci.

Plusieurs signaux peuvent tre connects au mme slot :


connect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError())); connect(calculator, SIGNAL(divisionByZero()), this, SLOT(handleMathError()));

Quand lun des signaux est mis, le slot est appel.

Un signal peut tre connect un autre signal :


connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SIGNAL(updateRecord(const QString &)));

Quand le premier signal est mis, le second est galement mis. En dehors de cette caractristique, les connexions signal-signal sont en tout point identiques aux connexions signal-slot.

Les connexions peuvent tre supprimes :


disconnect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError()));

Vous nen aurez que trs rarement besoin, parce que Qt supprime automatiquement toutes les connexions concernant un objet quand celui-ci est supprim.

24

Qt4 et C++ : Programmation dinterfaces GUI

Pour bien connecter un signal un slot (ou un autre signal), ils doivent avoir les mmes types de paramtre dans le mme ordre :
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)), this, SLOT(processReply(int, const QString &)));

Exceptionnellement, si un signal comporte plus de paramtres que le slot auquel il est connect, les paramtres supplmentaires sont simplement ignors :
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)), this, SLOT(checkErrorCode(int)));

Si les types de paramtre sont incompatibles, ou si le signal ou le slot nexiste pas, Qt mettra un avertissement au moment de lexcution si lapplication est gnre en mode dbogage. De mme, Qt enverra un avertissement si les noms de paramtre se trouvent dans les signatures du signal ou du slot. Jusqu prsent, nous navons utilis que des signaux et des slots avec des widgets. Cependant, le mcanisme en soi est implment dans QObject et ne se limite pas la programmation dinterfaces graphiques utilisateurs. Il peut tre employ par nimporte quelle sous-classe de QObject:
class Employee: public QObject { Q_OBJECT public: Employee() { mySalary = 0; } int salary() const { return mySalary; } public slots: void setSalary(int newSalary); signals: void salaryChanged(int newSalary); private: int mySalary; }; void Employee::setSalary(int newSalary) { if (newSalary!= mySalary) { mySalary = newSalary; emit salaryChanged(mySalary); } }

Vous remarquerez la manire dont le slot setSalary() est implment. Nous nmettons le signal salaryChanged() que si newSalary!= mySalary. Vous tes donc sr que les connexions cycliques ne dbouchent pas sur des boucles innies.

Chapitre 2

Crer des botes de dialogue

25

Systme de mta-objets de Qt
Lune des amliorations majeures de Qt a t lintroduction dans le langage C++ dun mcanisme permettant de crer des composants logiciels indpendants qui peuvent tre relis les uns aux autres sans quils ne sachent absolument rien sur les autres composants auxquels ils sont connects. Ce mcanisme est appel systme de mta-objets et propose deux services essentiels : les signaux-slots et lintrospection. La fonction dintrospection est ncessaire pour implmenter des signaux et des slots et permet aux programmeurs dapplications dobtenir des "mtainformations" sur les sous-classes de QObject lexcution, y compris la liste des signaux et des slots pris en charge par lobjet et le nom de sa classe. Le mcanisme supporte galement des proprits (pour le Qt Designer) et des traductions de texte (pour linternationalisation), et il pose les fondements de QSA (Qt Script for Applications). Le langage C++ standard ne propose pas de prise en charge des mta-informations dynamiques ncessaires pour le systme de mta-objets de Qt. Qt rsout ce problme en fournissant un outil, moc, qui analyse les dnitions de classe Q_OBJECT et rend les informations disponibles par le biais de fonctions C++. Etant donn que moc implmente toute sa fonctionnalit en utilisant un langage C++ pur, le systme de mta-objets de Qt fonctionne avec nimporte quel compilateur C++. Ce mcanisme fonctionne de la manire suivante :

La macro Q_OBJECT dclare certaines fonctions dintrospection qui doivent tre implmentes dans chaque sous-classe de QObject: metaObject(), tr(), qt_metacall() et quelques autres. Loutil moc de Qt gnre des implmentations pour les fonctions dclares par Q_OBJECT et pour tous les signaux. Les fonctions membres de QObject, telles que connect() et disconnect(), utilisent les fonctions dintrospection pour effectuer leurs tches.

Tout est gr automatiquement par qmake, moc et QObject, vous ne vous en souciez donc que trs rarement. Nanmoins, par curiosit, vous pouvez parcourir la documentation de la classe QMetaObject et analyser les chiers sources C++ gnrs par moc pour dcouvrir comment fonctionne limplmentation.

Conception rapide dune bote de dialogue


Qt est conu pour tre agrable et intuitif crire, et il nest pas inhabituel que des programmeurs dveloppent des applications Qt compltes en saisissant la totalit du code source C++. De nombreux programmeurs prfrent cependant utiliser une approche visuelle pour concevoir

26

Qt4 et C++ : Programmation dinterfaces GUI

les formulaires. Ils la trouvent en effet plus naturelle et plus rapide, et ils veulent tre en mesure de tester et de modier leurs conceptions plus rapidement et facilement quavec des formulaires cods manuellement. Le Qt Designer dveloppe les options disposition des programmeurs en proposant une fonctionnalit visuelle de conception. Le Qt Designer peut tre employ pour dvelopper tous les formulaires dune application ou juste quelques-uns. Les formulaires crs laide du Qt Designer tant uniquement constitus de code C++, le Qt Designer peut tre utilis avec une chane doutils traditionnelle et nimpose aucune exigence particulire au compilateur. Dans cette section, nous utiliserons le Qt Designer an de crer la bote de dialogue Go-to-Cell prsente en Figure 2.4. Quelle que soit la mthode de conception choisie, la cration dune bote de dialogue implique toujours les mmes tapes cls :

crer et initialiser les widgets enfants ; placer les widgets enfants dans des dispositions ; dnir lordre de tabulation ; tablir les connexions signal-slot ; implmenter les slots personnaliss de la bote de dialogue.

Figure 2.4 La bote de dialogue Go-to-Cell

Pour lancer le Qt Designer, cliquez sur Qt by Trolltech v4.x.y > Designer dans le menu Dmarrer sous Windows, saisissez designer dans la ligne de commande sous Unix ou doublecliquez sur Designer dans le Finder de Mac OS X. Quand le Qt Designer dmarre, une liste de modles safche. Cliquez sur le modle "Widget", puis sur OK. (Le modle "Dialog with Buttons Bottom" peut tre tentant, mais pour cet exemple nous crerons les boutons OK et Cancel manuellement pour vous expliquer le processus.) Vous devriez prsent vous trouver dans une fentre appele "Untitled". Par dfaut, linterface utilisateur du Qt Designer consiste en plusieurs fentres de haut niveau. Si vous prfrez une interface de style MDI, avec une fentre de haut niveau et plusieurs sousfentres, cliquez sur Edit > User Interface Mode > Docked Window (voir Figure 2.5). La premire tape consiste crer les widgets enfants et les placer sur le formulaire. Crez une tiquette, un diteur de lignes, un lment despacement horizontal et deux boutons de commande. Pour chaque lment, faites glisser son nom ou son icne depuis la bote des widgets du Qt Designer vers son emplacement sur le formulaire. Llment despacement, qui est invisible dans le formulaire nal, est afch dans le Qt Designer sous forme dun ressort bleu.

Chapitre 2

Crer des botes de dialogue

27

Figure 2.5 Le Qt Designer en mode dafchage fentres ancres sous Windows

Faites glisser le bas du formulaire vers le haut pour le rtrcir. Vous devriez voir un formulaire similaire celui de la Figure 2.6. Ne perdez pas trop de temps positionner les lments sur le formulaire ; les gestionnaires de disposition de Qt les disposeront prcisment par la suite.
Figure 2.6 Le formulaire avec quelques widgets

Congurez les proprits de chaque widget laide de lditeur de proprits du Qt Designer : 1. Cliquez sur ltiquette de texte. Assurez-vous que la proprit objectName est label et dnissez la proprit text en &Cell Location:. 2. Cliquez sur lditeur de lignes. Vriez que la proprit objectName est lineEdit. 3. Cliquez sur le premier bouton. Congurez la proprit objectName en okButton, la proprit enabled en false, la proprit text en OK et la proprit default en true. 4. Cliquez sur le second bouton. Dnissez la proprit objectName en cancelButton et la proprit text en Cancel. 5. Cliquez sur larrire-plan du formulaire pour slectionner ce dernier. Dnissez objectName en GoToCellDialog et windowTitle en Go to Cell. Tous les widgets sont correctement prsents, sauf ltiquette de texte, qui afche &Cell Location. Cliquez sur Edit > Edit Buddies pour passer dans un mode spcial qui vous permet de congurer les compagnons. Cliquez ensuite sur ltiquette et faites glisser la che rouge vers lditeur de lignes. Ltiquette devrait prsenter le texte "Cell Location" et lditeur de lignes devrait tre son widget compagnon. Cliquez sur Edit > Edit widgets pour quitter le mode des compagnons.

28

Qt4 et C++ : Programmation dinterfaces GUI

Figure 2.7 Le formulaire dont les proprits sont dnies

La prochaine tape consiste disposer les widgets sur le formulaire : 1. Cliquez sur ltiquette Cell Location et maintenez la touche Maj enfonce quand vous cliquez sur lditeur de lignes, de manire ce quils soient slectionns tous les deux. Cliquez sur Form > Lay Out Horizontally. 2. Cliquez sur llment despacement, maintenez la touche Maj enfonce et appuyez sur les boutons OK et Cancel du formulaire. Cliquez sur Form > Lay Out Horizontally. 3. Cliquez sur larrire-plan du formulaire pour annuler toute slection dlment, puis cliquez sur Form > Lay Out Vertically. 4. Cliquez sur Form > Ajust Size pour redimensionner le formulaire. Les lignes rouges qui apparaissent sur le formulaire montrent les dispositions qui ont t cres. Elles ne safchent pas lorsque le formulaire est excut.
Figure 2.8 Le formulaire avec les dispositions

Cliquez prsent sur Edit > Edit Tab Order. Un nombre apparatra dans un rectangle bleu ct de chaque widget qui peut devenir actif (voir Figure 2.9). Cliquez sur chaque widget dans lordre dans lequel vous voulez quils reoivent le focus, puis cliquez sur Edit > Edit widgets pour quitter le mode ddition de lordre de tabulation.
Figure 2.9 Dnir lordre de tabulation du formulaire

Pour avoir un aperu de la bote de dialogue, slectionnez loption Form > Preview du menu. Vriez lordre de tabulation en appuyant plusieurs fois sur la touche Tab. Fermez la bote de dialogue en appuyant sur le bouton de fermeture dans la barre de titre.

Chapitre 2

Crer des botes de dialogue

29

Enregistrez la bote de dialogue sous gotocelldialog.ui dans un rpertoire appel gotocell, et crez un chier main.cpp dans le mme rpertoire grce un diteur de texte ordinaire :
#include <QApplication> #include <QDialog> #include "ui_gotocelldialog.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Ui::GoToCellDialog ui; QDialog *dialog = new QDialog; ui.setupUi(dialog); dialog->show(); return app.exec(); }

Excutez maintenant qmake pour crer un chier .pro et un Makele (qmake -project; qmake goto-cell.pro). Loutil qmake est sufsamment intelligent pour dtecter le chier de linterface utilisateur gotocelldialog.ui et pour gnrer les rgles appropries du chier Makele. Il va donc appeler uic, le compilateur Qt de linterface utilisateur. Loutil uic convertit gotocelldialog.ui en langage C++ et intgre les rsultats dans ui_gotocelldialog.h. Le chier ui_gotocelldialog.h gnr contient la dnition de la classe Ui::GoToCellDialog qui est un quivalent C++ du chier gotocelldialog.ui. La classe dclare des variables membres qui stockent les widgets enfants et les dispositions du formulaire, et une fonction setupUi() qui initialise le formulaire. Voici la syntaxe de la classe gnre :
class Ui::GoToCellDialog { public: QLabel *label; QLineEdit *lineEdit; QSpacerItem *spacerItem; QPushButton *okButton; QPushButton *cancelButton; ...

void setupUi(QWidget *widget) { ... } };

Cette classe nhrite pas de nimporte quelle classe Qt. Quand vous utilisez le formulaire dans main.cpp, vous crez un QDialog et vous le transmettez setupUi().

30

Qt4 et C++ : Programmation dinterfaces GUI

Si vous excutez le programme maintenant, la bote de dialogue fonctionnera, mais pas exactement comme vous le souhaitiez : Le bouton OK est toujours dsactiv. Le bouton Cancel ne fait rien. Lditeur de lignes accepte nimporte quel texte, au lieu daccepter uniquement des emplacements de cellule valides. Pour faire fonctionner correctement la bote de dialogue, vous devrez crire du code. La meilleure approche consiste crer une nouvelle classe qui hrite la fois de QDialog et de Ui::GoToCellDialog et qui implmente la fonctionnalit manquante (ce qui prouve que tout problme logiciel peut tre rsolu simplement en ajoutant une autre couche dindirection). Notre convention de dnomination consiste attribuer cette nouvelle classe le mme nom que la classe gnre par uic, mais sans le prxe Ui::.

A laide dun diteur de texte, crez un chier nomm gotocelldialog.h qui contient le code suivant :
#ifndef GOTOCELLDIALOG_H #define GOTOCELLDIALOG_H #include <QDialog> #include "ui_gotocelldialog.h" class GoToCellDialog: public QDialog, public Ui::GoToCellDialog { Q_OBJECT public: GoToCellDialog(QWidget *parent = 0); private slots: void on_lineEdit_textChanged(); }; #endif

Limplmentation fait partie de gotocelldialog.cpp:


#include <QtGui> #include "gotocelldialog.h" GoToCellDialog::GoToCellDialog(QWidget *parent) : QDialog(parent) { setupUi(this); QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");

Chapitre 2

Crer des botes de dialogue

31

lineEdit->setValidator(new QRegExpValidator(regExp, this)); connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void GoToCellDialog::on_lineEdit_textChanged() { okButton->setEnabled(lineEdit->hasAcceptableInput()); }

Dans le constructeur, nous appelons setupUi() pour initialiser le formulaire. Grce lhritage multiple, nous pouvons accder directement aux membres de Ui::GoToCellDialog. Aprs avoir cr linterface utilisateur, setupUi() connectera galement automatiquement tout slot qui respecte la convention de dnomination on_Nomobjet_NomSignal() au signal nomSignal() correspondant de objectName. Dans notre exemple, cela signie que setupUi() tablira la connexion signal-slot suivante :
connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(on_lineEdit_textChanged()));

Toujours dans le constructeur, nous dnissons un validateur qui restreint la plage des valeurs en entre. Qt propose trois classes de validateurs :QIntValidator, QDoubleValidator et QRegExpValidator. Nous utilisons ici QRegExpValidator avec lexpression rgulire "[A-Za-z][1-9][0-9]{0,2}", qui signie : autoriser une lettre majuscule ou minuscule, suivie dun chiffre entre 1 et 9, puis de zro, un ou deux chiffres entre 0 et 9. (En guise dintroduction aux expressions rgulires, consultez la documentation de la classe QRegExp.) Si vous transmettez ceci au constructeur de QRegExpValidator, vous en faites un enfant de lobjet GoToCellDialog. Ainsi, vous navez pas besoin de prvoir la suppression de QRegExpValidator; il sera supprim automatiquement en mme temps que son parent. Le mcanisme parent-enfant de Qt est implment dans QObject. Quand vous crez un objet (un widget, un validateur, ou autre) avec un parent, le parent ajoute lobjet sa liste denfants. Quand le parent est supprim, il parcourt sa liste denfants et les supprime. Les enfants eux-mmes effacent ensuite tous leurs enfants, et ainsi de suite jusqu ce quil nen reste plus aucun. Ce mcanisme parent-enfant simplie nettement la gestion de la mmoire, rduisant les risques de fuites de mmoire. Les seuls objets que vous devrez supprimer explicitement sont les objets que vous crez avec new et qui nont pas de parent. Et si vous supprimez un objet enfant avant son parent, Qt supprimera automatiquement cet objet de la liste des enfants du parent. Sagissant des widgets, le parent a une signication supplmentaire : les widgets enfants sont afchs dans la zone du parent. Quand vous supprimez le widget parent, lenfant est effac de la mmoire mais galement de lcran. A la n du constructeur, nous connectons le bouton OK au slot accept() de QDialog et le bouton Cancel au slot reject(). Les deux slots ferment la bote de dialogue, mais accept() dnit la valeur de rsultat de la bote de dialogue en QDialog::Accepted (qui est gal 1),

32

Qt4 et C++ : Programmation dinterfaces GUI

et reject() congure la valeur en QDialog::Rejected (gal 0). Quand nous utilisons cette bote de dialogue, nous avons la possibilit dutiliser la valeur de rsultat pour voir si lutilisateur a cliqu sur OK et agir de faon approprie. Le slot on_lineEdit_textChanged() active ou dsactive le bouton OK, selon que lditeur de lignes contient un emplacement de cellule valide ou non. QLineEdit::hasAcceptableInput() emploie le validateur que nous avons dni dans le constructeur. Ceci termine la bote de dialogue. Vous pouvez dsormais rcrire main.cpp pour lutiliser :
#include <QApplication> #include "gotocelldialog.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); GoToCellDialog *dialog = new GoToCellDialog; dialog->show(); return app.exec(); }

Rgnrez lapplication (qmake project; qmake gotocell.pro) et excutez-la nouveau. Tapez "A12" dans lditeur de lignes et vous verrez que le bouton OK sactive. Essayez de saisir du texte alatoire pour vrier que le validateur effectue bien sa tche. Cliquez sur Cancel pour fermer la bote de dialogue. Lun des avantages du Qt Designer, cest que les programmeurs sont libres de modier la conception de leurs formulaires sans tre obligs de changer leur code source. Quand vous dveloppez un formulaire simplement en rdigeant du code C++, les modications apportes la conception peuvent vous faire perdre normment de temps. Grce au Qt Designer, vous gagnez en efcacit parce que uic rgnre simplement le code source pour tout formulaire modi. Linterface utilisateur de la bote de dialogue est enregistre dans un chier .ui (un format de chier bas sur le langage XML), alors que la fonctionnalit personnalise est implmente en sous-classant la classe gnre par uic.

Botes de dialogue multiformes


Nous avons vu comment crer des botes de dialogue qui afchent toujours les mmes widgets lors de leur utilisation. Dans certains cas, il est souhaitable de proposer des botes de dialogue dont la forme peut varier. Les deux types les plus courants de botes de dialogue multiformes sont les botes de dialogue extensibles et les botes de dialogue multipages. Ces deux types de botes de dialogue peuvent tre implments dans Qt, simplement dans du code ou par le biais du Qt Designer.

Chapitre 2

Crer des botes de dialogue

33

Les botes de dialogue extensibles ont habituellement une apparence simple, mais elles proposent un bouton de basculement qui permet lutilisateur dalterner entre les apparences simple et dveloppe de la bote de dialogue. Ces botes de dialogue sont gnralement utilises dans des applications qui tentent de rpondre la fois aux besoins des utilisateurs occasionnels et ceux des utilisateurs expriments, masquant les options avances moins que lutilisateur ne demande explicitement les voir. Dans cette section, nous utiliserons le Qt Designer an de crer la bote de dialogue extensible prsente en Figure 2.10. Cest une bote de dialogue Sort dans un tableur, o lutilisateur a la possibilit de slectionner une ou plusieurs colonnes trier. Lapparence simple de cette bote de dialogue permet lutilisateur de saisir une seule cl de tri, et son apparence dveloppe propose deux cls de tri supplmentaires. Grce au bouton More, lutilisateur bascule entre les apparences simple et dveloppe.
Figure 2.10 La bote de dialogue Sort dans ses deux versions, simple et dveloppe

Nous crerons le widget avec son apparence dveloppe dans le Qt Designer, et nous masquerons les cls secondaires et tertiaires lexcution. Le widget semble complexe, mais il est assez simple raliser dans le Qt Designer. Lastuce est de se charger dabord de la cl primaire, puis de la dupliquer deux fois pour obtenir les cls secondaires et tertiaires : 1. Cliquez sur File > New Form et slectionnez le modle "Dialog with Buttons Right". 2. Crez le bouton More et faites-le glisser dans la disposition verticale, sous llment despacement vertical. Dnissez la proprit text du bouton More en &More et sa proprit checkable en true. Congurez la proprit default du bouton OK en true. 3. Crez une zone de groupe, deux tiquettes, deux zones de liste droulante et un lment despacement horizontal, puis placez-les sur le formulaire. 4. Faites glisser le coin infrieur droit de la zone de groupe pour lagrandir. Puis dplacez les autres widgets dans la zone de groupe pour les positionner peu prs comme dans la Figure 2.11 (a).

34

Qt4 et C++ : Programmation dinterfaces GUI

5. Faites glisser le bord droit de la seconde zone de liste droulante, de sorte quelle soit environ deux fois plus grande que la premire zone de liste. 6. Dnissez la proprit title de la zone de groupe en &Primary Key, la proprit text de la premire tiquette en Column: et celle de la deuxime tiquette en Order:. 7. Cliquez du bouton droit sur la premire zone de liste droulante et slectionnez Edit Items dans le menu contextuel pour ouvrir lditeur de zone de liste droulante du Qt Designer. Crez un lment avec le texte "None". 8. Cliquez du bouton droit sur la seconde zone de liste droulante et slectionnez Edit Items. Crez les lments "Ascending" et "Descending". 9. Cliquez sur la zone de groupe, puis sur Form > Lay Out in a Grid. Cliquez nouveau sur la zone de groupe et sur Form > Adjust Size. Vous aboutirez la disposition afche dans la Figure 2.11 (b).
Figure 2.11 Disposer les enfants de la zone de groupe dans une grille

(a) Sans disposition

(b) Avec disposition

Si une disposition ne savre pas trs bonne ou si vous avez fait une erreur, vous pouvez toujours cliquer sur Edit > Undo ou Form > Break Layout, puis repositionner les widgets et ressayer.
Figure 2.12 Disposer les enfants du formulaire dans une grille

(a) Sans disposition

(b) Avec disposition

Chapitre 2

Crer des botes de dialogue

35

Nous allons maintenant ajouter les zones de groupe Secondary Key et Tertiary Key : 1. Prenez garde ce que la fentre soit assez grande pour accueillir les composants supplmentaires. 2. Maintenez la touche Ctrl enfonce (Alt sur Mac) et cliquez sur la zone de groupe Primary Key pour en crer une copie (et de son contenu) au-dessus de loriginal. Faites glisser la copie sous la zone de groupe originale en gardant toujours la touche Ctrl (ou Alt) enfonce. Rptez ce processus pour crer une troisime zone de groupe, en la faisant glisser sous la deuxime zone. 3. Transformez leurs proprits title en &Secondary Key et &Tertiary Key. 4. Crez un lment despacement vertical et placez-le entre la zone de la cl primaire et celle de la cl secondaire. 5. Disposez les widgets comme illustr en Figure 2.12 (a). 6. Cliquez sur le formulaire pour annuler la slection de tout widget, puis sur Form > Lay Out in a Grid. Le formulaire devrait dsormais correspondre celui de la Figure 2.12 (b). 7. Dnissez la proprit sizeHint des deux lments despacement verticaux en [20, 0]. La disposition de type grille qui en rsulte comporte deux colonnes et quatre lignes, ce qui fait un total de huit cellules. La zone de groupe Primary Key, llment despacement vertical le plus gauche, les zones de groupe Secondary Key et Tertiary Key occupent chacun une seule cellule. La disposition verticale qui contient les boutons OK, Cancel et More occupe deux cellules. Il reste donc deux cellules vides en bas droite de la bote de dialogue. Si ce nest pas le cas, annulez la disposition, repositionnez les widgets et essayez nouveau. Renommez le formulaire "SortDialog" et changez le titre de la fentre en "Sort".Dnissez les noms des widgets enfants comme dans la Figure 2.13.
Figure 2.13 Nommer les widgets du formulaire

primaryGroupBox primaryColumnCombo primaryOrderCombo

okButton cancelButton

moreButton secondaryGroupBox secondaryColumnCombo secondaryOrderCombo tertiaryGroupBox tertiaryColumnCombo tertiaryOrderCombo

36

Qt4 et C++ : Programmation dinterfaces GUI

Cliquez sur Edit > Edit Tab Order. Cliquez sur chaque zone de liste droulante de haut en bas, puis cliquez sur les boutons OK, Cancel et More situs droite. Cliquez sur Edit > Edit Widgets pour quitter le mode dition de lordre de tabulation. Maintenant que le formulaire a t conu, nous sommes prts le rendre fonctionnel en congurant certaines connexions signal-slot. Le Qt Designer vous permet dtablir des connexions entre les widgets qui font partie du mme formulaire. Nous devons tablir deux connexions. Cliquez sur Edit > Edit Signals/Slots pour passer en mode de connexion dans le Qt Designer. Les connexions sont reprsentes par des ches bleues entre les widgets du formulaire. Vu que nous avons choisi le modle "Dialog with Buttons Right", les boutons OK et Cancel sont dj connects aux slots accept() et reject() de QDialog. Les connexions sont galement rpertories dans lditeur de signal/slot du Qt Designer. Pour tablir une connexion entre deux widgets, cliquez sur le widget "expditeur" et faites glisser la che rouge vers le widget "destinataire".Une bote de dialogue souvre o vous pouvez choisir le signal et le slot connecter.
Figure 2.14 Connecter les widgets du formulaire

La premire connexion est tablir entre moreButton et secondaryGroupBox. Faites glisser la che rouge entre ces deux widgets, puis choisissez toggled(bool) comme signal et setVisible(bool) comme slot. Par dfaut, le Qt Designer ne rpertorie pas setVisible(bool) dans sa liste de slots, mais il apparatra si vous activez loption Show all signals and slots. Vous devez ensuite crer une connexion entre le signal toggled(bool) de moreButton et le slot setVisible(bool) de tertiaryGroupBox. Lorsque les connexions sont effectues, cliquez sur Edit > Edit Widgets pour quitter le mode de connexion.

Chapitre 2

Crer des botes de dialogue

37

Figure 2.15 Lditeur de connexions du Qt Designer

Enregistrez la bote de dialogue sous sortdialog.ui dans un rpertoire appel sort. Pour ajouter du code au formulaire, vous emploierez la mme technique dhritage multiple que celle utilise pour la bote de dialogue Go-to-Cell de la section prcdente. Crez tout dabord un chier sortdialog.h qui comporte les lments suivants :
#ifndef SORTDIALOG_H #define SORTDIALOG_H #include <QDialog> #include "ui_sortdialog.h" class SortDialog: public QDialog, public Ui::SortDialog { Q_OBJECT public: SortDialog(QWidget *parent = 0); void setColumnRange(QChar first, QChar last); }; #endif

Puis crez sortdialog.cpp:


1 2 3 4 5 6 7 8

#include <QtGui> #include "sortdialog.h" SortDialog::SortDialog(QWidget *parent) : QDialog(parent) { setupUi(this); secondaryGroupBox->hide(); tertiaryGroupBox->hide();

38

Qt4 et C++ : Programmation dinterfaces GUI

9 10 11 } 12 13 14 15 16 17 18 19 20

layout()->setSizeConstraint(QLayout::SetFixedSize); setColumnRange(A, Z); void SortDialog::setColumnRange(QChar first, QChar last) { primaryColumnCombo->clear(); secondaryColumnCombo->clear(); tertiaryColumnCombo->clear(); secondaryColumnCombo->addItem(tr("None")); tertiaryColumnCombo->addItem(tr("None")); primaryColumnCombo->setMinimumSize( secondaryColumnCombo->sizeHint()); QChar ch = first; while (ch <= last) { primaryColumnCombo->addItem(QString(ch)); secondaryColumnCombo->addItem(QString(ch)); tertiaryColumnCombo->addItem(QString(ch)); ch = ch.unicode() + 1; }

21 22 23 24 25 26 27 28 }

Le constructeur masque les zones secondaire et tertiaire de la bote de dialogue. Il dnit aussi la proprit sizeConstraint de la disposition du formulaire en QLayout::SetFixedSize, lutilisateur ne pourra donc pas la redimensionner. La disposition se charge ensuite de redimensionner automatiquement la bote de dialogue quand des widgets enfants sont afchs ou masqus, vous tre donc sr que la bote de dialogue sera toujours prsente dans sa taille optimale. Le slot setColumnRange() initialise le contenu des zones de liste droulante en fonction des colonnes slectionnes dans le tableur. Nous insrons un lment "None" dans ces zones de liste pour les cls secondaire et tertiaire (facultatives). Les lignes 19 et 20 prsentent un comportement subtil de la disposition. La fonction QWidget::sizeHint() retourne la taille "idale" dun widget, ce que le systme de disposition essaie de respecter. Ceci explique pourquoi les diffrents types de widgets, ou des widgets similaires avec un contenu diffrent, peuvent se voir attribuer des tailles diffrentes par le systme de disposition. Concernant les zones de liste droulante, cela signie que les zones secondaire et tertiaire qui contiennent "None" seront plus grandes que la zone primaire qui ne contient que des entres une lettre. Pour viter cette incohrence, nous dnissons la taille minimale de la zone de liste droulante primaire en taille idale de la zone secondaire. Voici une fonction de test main() qui congure la plage de manire inclure les colonnes C F, puis afche la bote de dialogue :
#include <QApplication> #include "sortdialog.h"

Chapitre 2

Crer des botes de dialogue

39

int main(int argc, char *argv[]) { QApplication app(argc, argv); SortDialog *dialog = new SortDialog; dialog->setColumnRange(C, F); dialog->show(); return app.exec(); }

Ceci termine la bote de dialogue extensible. Vous pouvez constater que ce type de bote de dialogue nest pas plus compliqu concevoir quune bote de dialogue ordinaire : tout ce dont vous avez besoin, cest un bouton de basculement, quelques connexions signal-slot supplmentaires et une disposition non redimensionnable. Dans des applications de production, il est assez frquent que le bouton qui contrle lextension afche le texte Advanced >>> quand seule la bote de dialogue de base est visible et Advanced <<< quand elle est dveloppe. Cest facile concevoir dans Qt en appelant setText() sur QPushButton ds quon clique dessus. Lautre type courant de bote de dialogue multiforme, les botes de dialogue multipages, est encore plus facile concevoir dans Qt, soit en crant le code, soit par le biais du Qt Designer. De telles botes de dialogue peuvent tre gnres de diverses manires.

Un QTabWidget peut tre exploit indpendamment. Il propose une barre donglets en haut qui contrle un QStackedWidget intgr. Un QListWidget et un QStackedWidget peuvent tre employs ensemble, avec llment en cours de QListWidget qui dtermine quelle page est afche par QStackedWidget, en connectant le signal QListWidget::currentRowChanged() au slot QStackedWidget::setCurrentIndex(). Un QTreeWidget peut tre utilis avec un QStackedWidget de la mme faon quavec un QListWidget. La classe QStackedWidget est aborde au Chapitre 6.

Botes de dialogue dynamiques


Les botes de dialogue dynamiques sont cres depuis les chiers .ui du Qt Designer au moment de lexcution. Au lieu de convertir le chier .ui en code C++ grce uic, vous pouvez charger le chier lexcution laide de la classe QUiLoader:
QUiLoader uiLoader; QFile file("sortdialog.ui"); QWidget *sortDialog = uiLoader.load(&file); if (sortDialog) { ... }

40

Qt4 et C++ : Programmation dinterfaces GUI

Vous pouvez accder aux widgets enfants du formulaire en utilisant QObject::findChild<T>():


QComboBox *primaryColumnCombo = sortDialog->findChild<QComboBox *>("primaryColumnCombo"); if (primaryColumnCombo) { ... }

La fonction findChild<T>() est une fonction membre modle qui retourne lobjet enfant qui correspond au nom et au type donn. Vu les limites du compilateur, elle nest pas disponible pour MSVC 6. Si vous devez utiliser le compilateur MSVC 6, appelez plutt la fonction globale qFindChild<T>() qui fonctionne exactement de la mme faon. La classe QUiLoader se situe dans une bibliothque part. Pour employer QUiLoader depuis une application Qt, vous devez ajouter cette ligne de code au chier .pro de lapplication :
CONFIG += uitools

Les botes de dialogue dynamiques vous permettent de modier la disposition dun formulaire sans recompiler lapplication. Elles peuvent aussi servir crer des applications client lger, o lexcutable intgre principalement un formulaire frontal et o tous les autres formulaires sont crs comme ncessaire.

Classes de widgets et de botes de dialogue intgres


Qt propose un ensemble complet de widgets intgrs et de botes de dialogue courantes adapts la plupart des situations. Dans cette section, nous allons prsenter une capture de la plupart dentre eux. Quelques widgets spcialiss ne sont tudis quultrieurement : les widgets de fentre principale comme QMenuBar, QToolBar et QStatusBar sont abords dans le Chapitre 3, et les widgets lis la disposition, tels que QSplitter et QScrollArea, sont analyss dans le Chapitre 6. La majorit des widgets intgrs et des botes de dialogue est prsente dans les exemples de ce livre. Dans les captures suivantes, les widgets sont afchs avec le style Plastique.
Figure 2.16 Les widgets bouton de Qt
QPushButton QToolButton QCheckBox QRadioButton

Qt propose quatre types de "boutons" : QPushButton, QToolButton, QCheckBox et QRadioButton. QPushButton et QToolButton sont le plus souvent ajouts pour initier une action quand on clique dessus, mais ils peuvent aussi se comporter comme des boutons de basculement

Chapitre 2

Crer des botes de dialogue

41

(clic pour enfoncer, clic pour restaurer). QCheckBox peut servir pour les options indpendantes on/off, alors que les QRadioButton sexcluent mutuellement.
Figure 2.17 Les widgets conteneurs une seule page de Qt

QGroupBox

QFrame

Les widgets conteneurs de Qt sont des widgets qui contiennent dautres widgets. QFrame peut aussi tre employ seul pour tracer simplement des lignes et il est hrit par la plupart des autres classes de widgets, dont QToolBox et QLabel.
Figure 2.18 Les widgets conteneurs multipages de Qt

QTabWidget

QToolBox

QTabWidget et QToolBox sont des widgets multipages. Chaque page est un widget enfant, et les pages sont numrotes en commenant 0.
Figure 2.19 Les widgets dafchage dlments de Qt

QListView(liste)

QTreeView

QListView(icnes)

QTableView

42

Qt4 et C++ : Programmation dinterfaces GUI

Les afchages dlments sont optimiss pour grer de grandes quantits de donnes et font souvent appel des barres de dlement. Le mcanisme de la barre de dlement est implment dans QAbstractScrollArea, une classe de base pour les afchages dlments et dautres types de widgets dlement. Qt fournit quelques widgets simplement destins la prsentation des informations. QLabel est le plus important dentre eux et peut tre employ pour afcher un texte enrichi (grce une syntaxe simple de style HTML) et des images. QTextBrowser est une sous-classe de QTextEdit en lecture seule qui prend en charge la syntaxe HTML de base, y compris les listes, les tables, les images et les liens hypertexte. LAssistant de Qt se sert de QTextBrowser pour prsenter la documentation lutilisateur.
Figure 2.20 Les widgets dafchage de Qt
QLabel(texte) QLCDNumber QProgressBar

QLabel (image)

QTextBrowser

Qt propose plusieurs widgets pour les entres de donnes. QLineEdit peut contrler son entre par le biais dun masque de saisie ou dun validateur. QTextEdit est une sous-classe de QAbstractScrollArea capable de modier de grandes quantits de texte. Qt met votre disposition un ensemble standard de botes de dialogue courantes pratiques pour demander lutilisateur de choisir une couleur, une police ou un chier ou dimprimer un document. Sous Windows et Mac OS X, Qt exploite les botes de dialogue natives plutt que ses propres botes de dialogue si possible. Une bote de message polyvalente et une bote de dialogue derreur qui conserve les messages afchs apparaissent. La progression des oprations longues peut tre indique dans un QProgressDialog ou QProgressBar prsent prcdemment. QInputDialog se rvle trs pratique quand une seule ligne de texte ou un seul chiffre est demand lutilisateur. Les widgets intgrs et les botes de dialogue courantes mettent votre disposition de nombreuses fonctionnalits prtes lemploi. Des exigences plus particulires peuvent souvent tre satisfaites en congurant les proprits du widget ou en connectant des signaux des slots et en implmentant un comportement personnalis dans les slots.

Chapitre 2

Crer des botes de dialogue

43

Figure 2.21 Les widgets dentre de Qt

QSpinBox

QDoubleSpinBox

QComboBox

QDateEdit

QTimeEdit

QDateTimeEdit

QScrollBar

QSlider

QLineEdit

QTextEdit

QDial

Figure 2.22 Les botes de dialogue relatives la couleur et la police de Qt

QColorDialog

QFontDialog

Figure 2.23 Les botes de dialogue relatives limpression et aux chiers de Qt


QPageSetupDialog

QFileDialog

QPrintDialog

44

Qt4 et C++ : Programmation dinterfaces GUI

Figure 2.24 Les botes de dialogue de feedback de Qt


QInputDialog QProgressDialog

QMessageBox

QErrorMessage

Dans certains cas, il est judicieux de crer un widget personnalis en partant de zro. Qt facilite normment ce processus, et les widgets personnaliss peuvent accder la mme fonction de dessin indpendante de la plate-forme que les widgets intgrs de Qt. Les widgets personnaliss peuvent mme tre intgrs par le biais du Qt Designer, de sorte quils puissent tre employs de la mme faon que les widgets intgrs de Qt. Le Chapitre 5 vous explique comment crer des widgets personnaliss.