• 50 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

course.header.alt.is_certifying

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

Mis à jour le 02/08/2019

Utilisez les widgets

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Voilà un moment que nous avons commencé à nous intéresser à Qt, je vous parle en long en large et en travers de widgets, mais jusqu'ici nous n'avions toujours pas pris le temps de faire un tour d'horizon rapide de ce qui existait.

Il est maintenant temps de faire une « pause » et de regarder ce qui existe en matière de widgets. Nous étudierons cependant seulement les principaux widgets ici. Pourquoi ne les verrons-nous pas tous ? Parce qu'il en existe un grand nombre et que certains sont rarement utilisés. D'autres sont parfois tellement complexes qu'ils nécessiteraient un chapitre entier pour les étudier.

Néanmoins, avec ce que vous allez voir, vous aurez largement de quoi faire pour créer la quasi-totalité des fenêtres que vous voulez !

Les fenêtres

Avec Qt, tout élément de la fenêtre est appelé un widget. La fenêtre elle-même est considérée comme un widget.

Dans le code, les widgets sont des classes qui héritent toujours deQWidget(directement ou indirectement). C'est donc une classe de base très importante et vous aurez probablement très souvent besoin de lire la doc de cette classe.

Quelques rappels sur l'ouverture d'une fenêtre

Cela fait plusieurs chapitres que l'on crée une fenêtre dans nos programmes à l'aide d'un objet de typeQWidget. Cela signifie-t-il queQWidget= Fenêtre ?

Non. En fait, un widget qui n'est contenu dans aucun autre widget est considéré comme une fenêtre.
Donc quand on écrit juste ce code très simple :

#include <QApplication>
#include <QWidget>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget fenetre;
    fenetre.show();

    return app.exec();
}

… cela affiche une fenêtre vide :

Fenêtre vide
Fenêtre vide

C'est comme cela que Qt fonctionne. C'est un peu déroutant au début, mais après on apprécie au contraire que cela ait été pensé ainsi.

Donc si je comprends bien, il n'y a pas de classeQFenetreou quelque chose du genre ?

Tout à fait, il n'y a pas de classe du genreQFenetrecar n'importe quel widget peut servir de fenêtre. Pour Qt, c'est le widget qui n'a pas de parent qui sera considéré comme étant la fenêtre. À ce titre, unQPushButtonou unQLineEditpeuvent être considérés comme des fenêtres s'ils n'ont pas de widget parent.

Toutefois, il y a deux classes de widgets que j'aimerais mettre en valeur :

  • QMainWindow: c'est un widget spécial qui permet de créer la fenêtre principale de l'application. Une fenêtre principale peut contenir des menus, une barre d'outils, une barre d'état, etc.

  • QDialog: c'est une classe de base utilisée par toutes les classes de boîtes de dialogue qu'on a vues il y a quelques chapitres. On peut aussi s'en servir directement pour ouvrir des boîtes de dialogue personnalisées.

La fenêtre principaleQMainWindowmérite un chapitre entier à elle toute seule (et elle en aura un). Nous pourrons alors tranquillement passer en revue la gestion des menus, de la barre d'outils et de la barre d'état.

La fenêtreQDialogpeut être utilisée pour ouvrir une boîte de dialogue générique à personnaliser. Une boîte de dialogue est une fenêtre, généralement de petite taille, dans laquelle il y a peu d'informations.
La classeQDialoghérite deQWidgetcomme tout widget qui se respecte et elle y est même très similaire. Elle y ajoute peu de choses, parmi lesquelles la gestion des fenêtres modales (une fenêtre par-dessus toutes les autres, qui doit être remplie avant de pouvoir accéder aux autres fenêtres de l'application).

Nous allons ici étudier ce que l'on peut faire d'intéressant avec la classe de baseQWidgetqui permet déjà de réaliser la plupart des fenêtres que l'on veut.
Nous verrons ensuite ce qu'on peut faire avec les fenêtres de typeQDialog. Quant àQMainWindow, ce sera pour un autre chapitre, comme je vous l'ai dit.

Une fenêtre avecQWidget

Pour commencer, je vous invite à ouvrir la documentation deQWidgeten même temps que vous lisez ce chapitre.

Documentation de QWidget

Vous remarquerez queQWidgetest la classe mère d'un grrrrand nombre d'autres classes.
LesQWidgetdisposent de beaucoup de propriétés et de méthodes. Donc tous les widgets disposent de ces propriétés et méthodes.

On peut découper les propriétés en deux catégories :

  • celles qui valent pour tous les types de widgets et pour les fenêtres ;

  • celles qui n'ont de sens que pour les fenêtres.

Jetons un coup d'œil à celles qui me semblent les plus intéressantes. Pour avoir la liste complète, il faudra recourir à la documentation, je ne compte pas tout répéter ici !

Les propriétés utilisables pour tous les types de widgets, y compris les fenêtres

Je vous fais une liste rapide pour extraire quelques propriétés qui pourraient vous intéresser. Pour savoir comment vous servir de toutes ces propriétés, lisez le prototype que vous donne la documentation.

  • cursor: curseur de la souris à afficher lors du survol du widget. La méthodesetCursorattend que vous lui envoyiez un objet de typeQCursor. Certains curseurs classiques (comme le sablier) sont prédéfinis dans une énumération. La documentation vous propose un lien vers cette énumération.

  • enabled: indique si le widget est activé, si on peut le modifier. Un widget désactivé est généralement grisé. Si vous appliquezsetEnabled(false)à toute la fenêtre, c'est toute la fenêtre qui devient inutilisable.

  • height: hauteur du widget.

  • size: dimensions du widget. Vous devrez indiquer la largeur et la hauteur.

  • visible: contrôle la visibilité du widget.

  • width: largeur.

N'oubliez pas : pour modifier une de ces propriétés, préfixez la méthode par unset. Exemple :

maFenetre.setWidth(200);

Ces propriétés sont donc valables pour tous les widgets, y compris les fenêtres. Si vous appliquez unsetWidthsur un bouton, cela modifiera la largeur du bouton. Si vous appliquez cela sur une fenêtre, c'est la largeur de la fenêtre qui sera modifiée.

Les propriétés utilisables uniquement sur les fenêtres

Ces propriétés sont faciles à reconnaître, elles commencent toutes parwindow.
Elles n'ont de sens que si elles sont appliquées aux fenêtres.

    • windowFlags: une série d'options contrôlant le comportement de la fenêtre. Il faut consulter l'énumérationQt::WindowTypepour connaître les différents types disponibles. Vous pouvez aussi consulter l'exemple Window Flags du programme « Qt Examples and Demos ».

Par exemple pour afficher une fenêtre de type « Outil » avec une petite croix et pas de possibilité d'agrandissement ou de réduction (figure suivante) :

fenetre.setWindowFlags(Qt::Tool);

C'est par là aussi qu'on passe pour que la fenêtre reste par-dessus toutes les autres fenêtres du système (avec le flagQt::WindowStaysOnTopHint).

  • windowIcon: l'icône de la fenêtre. Il faut envoyer un objet de type QIcon, qui lui-même accepte un nom de fichier à charger. Cela donne le code suivant pour charger le fichier icone.pngsitué dans le même dossier que l'application  :

fenetre.setWindowIcon(QIcon("icone.png"));
  • windowTitle: le titre de la fenêtre, affiché en haut :

fenetre.setWindowTitle("Le Programme du Zéro v0.0");
Une fenêtre de type « Tool »
Une icône pour la fenêtre
Une fenêtre avec un titre
Une fenêtre avec un titre

Une fenêtre avecQDialog

QDialogest un widget spécialement conçu pour générer des fenêtres de type « boîte de dialogue ».

Quelle est la différence avec une fenêtre créée à partir d'unQWidget?

En général lesQDialogsont des petites fenêtres secondaires : des boîtes de dialogue.
Elles proposent le plus souvent un choix simple entre :

  • Valider ;

  • Annuler.

LesQDialogsont rarement utilisées pour gérer la fenêtre principale. Pour cette fenêtre, on préférera utiliserQWidgetou carrémentQMainWindowsi on a besoin de l'artillerie lourde.

LesQDialogpeuvent être de 2 types :

  • modales : on ne peut pas accéder aux autres fenêtres de l'application lorsqu'elles sont ouvertes ;

  • non modales : on peut toujours accéder aux autres fenêtres.

Par défaut, lesQDialogsont modales.
Elles disposent en effet d'une méthodeexec()qui ouvre la boîte de dialogue de manière modale. Il s'avère d'ailleurs qu'exec()est un slot (très pratique pour effectuer une connexion cela !).

Je vous propose d'essayer de pratiquer de la manière suivante : nous allons ouvrir une fenêtre principaleQWidgetqui contiendra un bouton. Lorsqu'on cliquera sur ce bouton, il ouvrira une fenêtre secondaire de typeQDialog.

Notre objectif est d'ouvrir une fenêtre secondaire après un clic sur un bouton de la fenêtre principale.
La fenêtre secondaire, de typeQDialog, affichera seulement une image pour cet exemple.

#include <QApplication>
#include <QtWidgets>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget fenetre;
        QPushButton *bouton = new QPushButton("Ouvrir la fenêtre", &fenetre);


    QDialog secondeFenetre (&fenetre);
        QVBoxLayout *layout = new QVBoxLayout;
        QLabel *image = new QLabel(&secondeFenetre);
        image->setPixmap(QPixmap("icone.png"));
        layout->addWidget(image);
        secondeFenetre.setLayout(layout);


    QWidget::connect(bouton, SIGNAL(clicked()), &secondeFenetre, SLOT(exec()));
    fenetre.show();

    return app.exec();
}

Au départ, la fenêtre principale s'affiche :

La fenêtre principale

Si vous cliquez sur le bouton, la boîte de dialogue s'ouvre :

La boîte de dialogue
La boîte de dialogue

Comme elle est modale, vous remarquerez que vous ne pouvez pas accéder à la fenêtre principale tant qu'elle est ouverte.

Si vous voulez en savoir plus sur les QDialog, vous savez ce qu'il vous reste à faire : tout est dans la documentation.

Les boutons

Nous allons maintenant étudier la catégorie des widgets « boutons ». Nous allons passer en revue :

  • QPushButton: un bouton classique, que vous avez déjà largement eu l'occasion de manipuler ;

  • QRadioButton: un bouton « radio », pour un choix à faire parmi une liste ;

  • QCheckBox: une case à cocher (on considère que c'est un bouton en GUI Design).

Tous ces widgets héritent deQAbstractButtonqui lui-même hérite deQWidget, qui finalement hérite deQObject(figure suivante).

L'héritage des boutons
L'héritage des boutons

Comme l'indique son nom, QAbstractButtonest une classe abstraite. Si vous vous souvenez des épisodes précédents de notre passionnant feuilleton, une classe abstraite est une classe… qu'on ne peut pas instancier, bravo !
On ne peut donc pas créer d'objets de type QAbstractButton, il faut forcément utiliser une des classes filles. QAbstractButtonsert donc juste de modèle de base pour ses classes filles.

QPushButton: un bouton

Le QPushButtonest l'élément le plus classique et le plus commun des fenêtres (je ne vous fais pas l'offense de vous expliquer à quoi sert un bouton):

QPushButton

Commençons par un rappel important, indiqué par la documentation :QPushButtonhérite deQAbstractButton. Et c'est vraiment une info importante car vous serez peut-être surpris de voir queQPushButtoncontient peu de méthodes qui lui sont propres. C'est normal, une grande partie d'entre elles se trouvent dans sa classe parenteQAbstractButton.

Un bouton émet un signalclicked()quand on l'active. C'est le signal le plus communément utilisé.

On note aussi les signauxpressed()(bouton enfoncé) etreleased()(bouton relâché), mais ils sont plus rares.

QCheckBox: une case à cocher

Une case à cocherQCheckBoxest généralement associée à un texte de libellé comme à la figure suivante.

Une case à cocher

On définit le libellé de la case lors de l'appel du constructeur :

#include <QApplication>
#include <QWidget>
#include <QCheckBox>


int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget fenetre;
    QCheckBox *checkbox = new QCheckBox("J'aime les frites", &fenetre);
    fenetre.show();

    return app.exec();
}

La case à cocher émet le signalstateChanged(bool)lorsqu'on modifie son état. Le booléen en paramètre nous permet de savoir si la case est maintenant cochée ou décochée.

Si vous voulez vérifier à un autre moment si la case est cochée, appelezisChecked()qui renvoie un booléen.

On peut aussi faire des cases à cocher à trois états (le troisième état étant l'état grisé). Renseignez-vous sur la propriététristatepour apprendre comment faire. Notez que ce type de case à cocher est relativement rare.

Enfin, sachez que si vous avez plusieurs cases à cocher, vous pouvez les regrouper au sein d'uneQGroupBox.

QRadioButton: les boutons radio

C'est une case à cocher particulière : une seule case peut être cochée à la fois parmi une liste (figure suivante).

Un bouton radio

Les boutons radio qui ont le même widget parent sont mutuellement exclusifs. Si vous en cochez un, les autres seront automatiquement décochés.

En général, on place les boutons radio dans uneQGroupBox. Utiliser desQGroupBoxdifférentes vous permet de séparer les groupes de boutons radio.

Voici un exemple d'utilisation d'uneQGroupBox(qui contient un layout herbergeant lesQRadioButton) :

#include <QApplication>
#include <QtWidgets>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget fenetre;
    QGroupBox *groupbox = new QGroupBox("Votre plat préféré", &fenetre);

    QRadioButton *steacks = new QRadioButton("Les steacks");
    QRadioButton *hamburgers = new QRadioButton("Les hamburgers");
    QRadioButton *nuggets = new QRadioButton("Les nuggets");

    steacks->setChecked(true);

    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->addWidget(steacks);
    vbox->addWidget(hamburgers);
    vbox->addWidget(nuggets);

    groupbox->setLayout(vbox);
    groupbox->move(5, 5);

    fenetre.show();

    return app.exec();
}

Les boutons radio sont placés dans un layout qui est lui-même placé dans la groupbox, qui est elle-même placée dans la fenêtre (figure suivante). Pfiou ! Le concept des widgets conteneurs est ici utilisé à fond !
Et encore, je n'ai pas fait de layout pour la fenêtre, ce qui fait que la taille initiale de la fenêtre est un peu petite. Mais ce n'est pas grave, c'est pour l'exemple (j'ai quand même une nourriture plus équilibrée que ne le laisse suggérer cette dernière capture d'écran, je vous rassure. ;)

Plusieurs boutons radio
Plusieurs boutons radio

Les afficheurs

Parmi les widgets afficheurs, on compte principalement :

  • QLabel: le plus important, un widget permettant d'afficher du texte ou une image ;

  • QProgressBar: une barre de progression.

Etudions-les en chœur, sans heurts, dans la joie et la bonne humeur !

QLabel: afficher du texte ou une image

C'est vraiment LE widget de base pour afficher du texte à l'intérieur de la fenêtre (figure suivante).
Nous l'avons déjà utilisé indirectement auparavant, via les cases à cocher ou encore les layouts de formulaire.

QLabel
QLabel

Un QLabelpeut afficher plusieurs types d'éléments :

  • du texte (simple ou enrichi) ;

  • une image.

Affichez un texte simple

Rien de plus simple, on utilisesetText():

label->setText("Bonjour les Zéros !");

Mais on peut aussi afficher un texte simple dès l'appel au constructeur, comme ceci :

QLabel *label = new QLabel("Bonjour les Zéros !", &fenetre);

Le résultat est le même que la capture d'écran que je vous ai montrée plus tôt (figure suivante).

Vous pouvez jeter aussi un coup d'œil à la propriété alignment, qui permet de définir l'alignement du texte dans le libellé.

Affichez une image

Vous pouvez demander à ce que leQLabelaffiche une image.
Comme il n'y a pas de constructeur qui accepte une image en paramètre, on va appeler le constructeur qui prend juste un pointeur vers la fenêtre parente.

Nous demanderons ensuite à ce que le libellé affiche une image à l'aide desetPixmap.
Cette méthode attend un objet de typeQPixmap. Après lecture de la documentation surQPixmap, il s'avère que cette classe a un constructeur qui accepte le nom du fichier à charger sous forme de chaîne de caractères.

QLabel *label = new QLabel(&fenetre);
label->setPixmap(QPixmap("icone.png"));

Pour que cela fonctionne, l'icône doit se trouver dans le même dossier que l'exécutable (figure suivante).

Une image dans un label
Une image dans un label

QProgressBar: une barre de progression

Les barres de progression sont gérées parQProgressBar. Cela permet d'indiquer à l'utilisateur l'avancement des opérations :

QProgressBar

Voici quelques propriétés utiles de la barre de progression :

  • maximum: la valeur maximale que peut prendre la barre de progression ;

  • minimum: la valeur minimale que peut prendre la barre de progression ;

  • value: la valeur actuelle de la barre de progression.

On utilisera doncsetValuepour changer la valeur de la barre de progression. Par défaut les valeurs sont comprises entre 0 et 100%.

UneQProgressBarenvoie un signalvalueChanged()lorsque sa valeur a été modifiée.

Les champs

Nous allons maintenant faire le tour des widgets qui permettent de saisir des données. C'est la catégorie de widgets la plus importante.

Encore une fois, nous ne verrons pas tout, seulement les principaux d'entre eux :

  • QLineEdit: champ de texte à une seule ligne ;

  • QTextEdit: champ de texte à plusieurs lignes pouvant afficher du texte mis en forme ;

  • QSpinBox: champ de texte adapté à la saisie de nombre entiers ;

  • QDoubleSpinBox: champ de texte adapté à la saisie de nombre décimaux ;

  • QSlider: curseur qui permet de sélectionner une valeur ;

  • QComboBox: liste déroulante.

QLineEdit: champ de texte à une seule ligne

Nous avons utilisé ce widget comme classe d'exemple lors du chapitre sur la lecture de la documentation de Qt, vous vous souvenez ?

UnQLineEditest un champ de texte sur une seule ligne (figure suivante).

QLineEdit

Son utilisation est, dans la plupart des cas, assez simple. Voici quelques propriétés à connaître :

  • text: permet de récupérer/modifier le texte contenu dans le champ.

  • alignment: alignement du texte à l'intérieur.

  • echoMode: type d'affichage du texte. Il faudra utiliser l'énumérationEchoModepour indiquer le type d'affichage. Par défaut, les lettres saisies sont affichées mais on peut aussi faire en sorte que les lettres soient masquées, pour les mots de passe par exemple.

lineEdit->setEchoMode(QLineEdit::Password);
  • inputMask: permet de définir un masque de saisie, pour obliger l'utilisateur à fournir une chaîne répondant à des critères précis (par exemple, un numéro de téléphone ne doit pas contenir de lettres). Vous pouvez aussi jeter un coup d'œil aux validators qui sont un autre moyen de valider la saisie de l'utilisateur.

  • maxLength: le nombre de caractères maximum qui peuvent être saisis.

  • readOnly: le contenu du champ de texte ne peut être modifié. Cette propriété ressemble àenabled(définie dansQWidget) mais, avecreadOnly, on peut quand même copier-coller le contenu duQLineEdittandis qu'avecenabled, le champ est complètement grisé et on ne peut pas récupérer son contenu.

On note aussi plusieurs slots qui permettent de couper/copier/coller/vider/annuler le champ de texte.

Enfin, certains signaux commereturnPressed()(l'utilisateur a appuyé sur Entrée) outextChanged()(l'utilisateur a modifié le texte) peuvent être utiles dans certains cas.

QTextEdit: champ de texte à plusieurs lignes

Ce type de champ est similaire à celui qu'on vient de voir, à l'exception du fait qu'il gère l'édition sur plusieurs lignes et, en particulier, qu'il autorise l'affichage de texte enrichi (HTML). Voici unQTextEdit

QTextEdit
QTextEdit

Il y a un certain nombre de choses que l'on pourrait voir sur lesQTextEditmais ce serait un peu trop long pour ce chapitre, qui vise plutôt à passer rapidement en revue les widgets.

Notez les propriétésplainTextethtmlqui permettent de récupérer et modifier le contenu respectivement sous forme de texte simple et sous forme de texte enrichi en HTML. Tout dépend de l'utilisation que vous en faites : normalement, dans la plupart des cas, vous utiliserez plutôtplainText.

QSpinBox: champ de texte de saisie d'entiers

UneQSpinBoxest un champ de texte (typeQLineEdit) qui permet d'entrer uniquement un nombre entier et qui dispose de petits boutons pour augmenter ou diminuer la valeur :

QSpinBox

QSpinBoxhérite deQAbstractSpinBox(tiens, encore une classe abstraite). Vérifiez donc aussi la documentation deQAbstractSpinBoxpour connaître toutes les propriétés de la spinbox.

Voici quelques propriétés intéressantes :

  • accelerated: permet d'autoriser la spinbox a accélérer la modification du nombre si on appuie longtemps sur le bouton.

  • minimum: valeur minimale que peut prendre la spinbox.

  • maximum: valeur maximale que peut prendre la spinbox.

  • singleStep: pas d'incrémentation (par défaut de 1). Si vous voulez que les boutons fassent varier la spinbox de 100 en 100, c'est cette propriété qu'il faut modifier !

  • value: valeur contenue dans la spinbox.

  • prefix: texte à afficher avant le nombre.

  • suffix: texte à afficher après le nombre.

QDoubleSpinBox: champ de texte de saisie de nombres décimaux

LeQDoubleSpinBox(figure suivante) est très similaire auQSpinBox, à la différence près qu'il travaille sur des nombres décimaux (des double).

QDoubleSpinBox

On retrouve la plupart des propriétés deQSpinBox. On peut rajouter la propriétédecimalsqui gère le nombre de chiffres après la virgule affichés par leQDoubleSpinBox.

QSlider: un curseur pour sélectionner une valeur

UnQSliderse présente sous la forme d'un curseur permettant de sélectionner une valeur numérique :

QSlider

QSliderhérite deQAbstractSlider(damned, encore une classe abstraite) qui propose déjà un grand nombre de fonctionnalités de base.

Beaucoup de propriétés sont les mêmes queQSpinBox, je ne les reprendrai donc pas ici.
Notons la propriétéorientationqui permet de définir l'orientation du slider (verticale ou horizontale).

Jetez un coup d'œil en particulier à ses signaux car on connecte en général le signalvalueChanged(int)au slot d'autres widgets pour répercuter la saisie de l'utilisateur.
Nous avions d'ailleurs manipulé ce widget lors du chapitre sur les signaux et les slots.

QComboBox: une liste déroulante

UneQComboBoxest une liste déroulante :

QComboBox

On ajoute des valeurs à la liste déroulante avec la méthodeaddItem:

QComboBox *liste = new QComboBox(&fenetre);
liste->addItem("Paris");
liste->addItem("Londres");
liste->addItem("Singapour");
liste->addItem("Tokyo");

On dispose de propriétés permettant de contrôler le fonctionnement de laQComboBox:

    • count: nombre d'éléments dans la liste déroulante.

    • currentIndex: numéro d'indice de l'élément actuellement sélectionné. Les indices commencent à 0. Ainsi, sicurrentIndexrenvoie 2, c'est que « Singapour » a été sélectionné dans l'exemple précédent.

    • currentText: texte correspondant à l'élément sélectionné. Si on a sélectionné « Singapour », cette propriété contient donc « Singapour ».

    • editable: indique si le widget autorise l'ajout de valeurs personnalisées ou non. Par défaut, l'ajout de nouvelles valeurs est interdit.

Si le widget est éditable, l'utilisateur pourra entrer de nouvelles valeurs dans la liste déroulante. Elle se comportera donc aussi comme un champ de texte. L'ajout d'une nouvelle valeur se fait en appuyant sur la touche « Entrée ». Les nouvelles valeurs sont placées par défaut à la fin de la liste.

LaQComboBoxémet des signaux commecurrentIndexChanged()qui indique qu'un nouvel élément a été sélectionné ethighlighted()qui indique l'élément survolé par la souris (ces signaux peuvent envoyer unintpour donner l'indice de l'élément ou unQStringpour le texte).

Les conteneurs

Normalement, n'importe quel widget peut en contenir d'autres.
Cependant, certains widgets ont été créés spécialement pour pouvoir en contenir d'autres :

  • QFrame: un widget pouvant avoir une bordure ;

  • QGroupBox: un widget (que nous avons déjà utilisé) adapté à la gestion des groupes de cases à cocher et de boutons radio ;

  • QTabWidget: un widget gérant plusieurs pages d'onglets.

QFrameest simple à comprendre, je vous renvoie donc vers la documentation. Vous y apprendrez à choisir le type de bordure qui vous convient le mieux. À part cela, ce widget ne fait rien de particulier, on l'utilise simplement pour regrouper d'autres widgets à l'intérieur.

Quant àQGroupBox, nous l'avons déjà étudié un peu plus tôt, je vous renvoie donc aux exemples précédents.

Intéressons-nous ici plus précisément auQTabWidget(système d'onglets), qui est un peu plus délicat à manipuler.

LeQTabWidgetpropose une gestion de plusieurs pages de widgets, organisées sous forme d'onglets :

QTabWidget
QTabWidget

Ce widget-conteneur est sensiblement plus difficile à utiliser que les autres. En effet, il ne peut contenir qu'un widget par page.

Quoi ? On ne peut pas afficher plus d'un widget par page ?!
Mais c'est tout nul !

Sauf… qu'un widget peut en contenir d'autres !
Et si on utilise un layout pour organiser le contenu de ce widget, on peut arriver rapidement à une super présentation. Le tout est de savoir combiner tout ce qu'on a appris jusqu'ici.

D'après le texte d'introduction de la doc deQTabWidget, ce conteneur doit être utilisé de la façon suivante :

  1. Créer unQTabWidget.

  2. Créer unQWidgetpour chacune des pages (chacun des onglets) duQTabWidget, sans leur indiquer de widget parent.

  3. Placer des widgets enfants dans chacun de cesQWidgetpour peupler le contenu de chaque page. Utiliser un layout pour positionner les widgets de préférence.

  4. Appeler plusieurs foisaddTab()pour créer les pages d'onglets en indiquant l'adresse duQWidgetqui contient la page à chaque fois.

Bon, c'est un peu plus délicat comme vous pouvez le voir, mais il faut bien un peu de difficulté, ce chapitre était trop facile. ;-)

Si on fait tout dans l'ordre, vous allez voir que l'on n'aura pas de problème.
Je vous propose de lire ce code que j'ai créé, qui illustre l'utilisation duQTabWidget. Il est un peu long mais il est commenté et vous devriez arriver à le digérer.

#include <QApplication>
#include <QtWidgets>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget fenetre;

    // 1 : Créer le QTabWidget
    QTabWidget *onglets = new QTabWidget(&fenetre);
    onglets->setGeometry(30, 20, 240, 160);

    // 2 : Créer les pages, en utilisant un widget parent pour contenir chacune des pages
    QWidget *page1 = new QWidget;
    QWidget *page2 = new QWidget;
    QLabel *page3 = new QLabel; // Comme un QLabel est aussi un QWidget (il en hérite), on peut aussi s'en servir de page

    // 3 : Créer le contenu des pages de widgets

        // Page 1

        QLineEdit *lineEdit = new QLineEdit("Entrez votre nom");
        QPushButton *bouton1 = new QPushButton("Cliquez ici");
        QPushButton *bouton2 = new QPushButton("Ou là…");

        QVBoxLayout *vbox1 = new QVBoxLayout;
        vbox1->addWidget(lineEdit);
        vbox1->addWidget(bouton1);
        vbox1->addWidget(bouton2);

        page1->setLayout(vbox1);

        // Page 2

        QProgressBar *progress = new QProgressBar;
        progress->setValue(50);
        QSlider *slider = new QSlider(Qt::Horizontal);
        QPushButton *bouton3 = new QPushButton("Valider");

        QVBoxLayout *vbox2 = new QVBoxLayout;
        vbox2->addWidget(progress);
        vbox2->addWidget(slider);
        vbox2->addWidget(bouton3);

        page2->setLayout(vbox2);

        // Page 3 (je ne vais afficher qu'une image ici, pas besoin de layout)

        page3->setPixmap(QPixmap("icone.png"));
        page3->setAlignment(Qt::AlignCenter);

    // 4 : ajouter les onglets au QTabWidget, en indiquant la page qu'ils contiennent
    onglets->addTab(page1, "Coordonnées");
    onglets->addTab(page2, "Progression");
    onglets->addTab(page3, "Image");

    fenetre.show();

    return app.exec();
}

Vous devriez retrouver chacune des étapes que j'ai mentionnées plus haut :

    1. Je crée d'abord leQTabWidgetque je positionne ici de manière absolue sur la fenêtre (mais je pourrais aussi utiliser un layout).

    2. Ensuite, je crée les pages pour chacun de mes onglets. Ces pages sont matérialisées par desQWidget.

Vous noterez que, pour la dernière page, je n'utilise pas un QWidgetmais un QLabel. Cela revient au même et c'est compatible car QLabelhérite de QWidget. Sur la dernière page, je me contenterai d'afficher une image.

  1. Je crée ensuite le contenu de chacune de ces pages que je dispose à l'aide de layouts verticaux (sauf pour la page 3 qui n'est constituée que d'un widget). Là il n'y a rien de nouveau.

  2. Enfin, j'ajoute les onglets avec la méthode addTab(). Je dois indiquer le libellé de l'onglet ainsi qu'un pointeur vers le « widget-page » de cette page.

Résultat, on a un super système comportant trois d'onglets avec tout plein de widgets dedans  !

Le QTabWidget en action
Le QTabWidget en action

Je vous conseille de vous entraîner à créer vous aussi un QTabWidget. C'est un bon exercice, et c'est l'occasion de réutiliser la plupart des widgets que l'on a vus dans ce chapitre.

En résumé

  • Avec Qt, tout est considéré comme un widget : les boutons, les champs de texte, les images… et même la fenêtre !

  • Qt propose de très nombreux widgets. Pour apprendre à les utiliser, le plus simple est de lire leur page de documentation. Il est inutile d'essayer de retenir par cœur le nom de toutes les méthodes.

  • Un widget peut en contenir un autre. Certains widgets sont spécifiquement conçus pour en contenir d'autres, on les appelle les conteneurs.

  • Un widget qui n'a pas de parent s'affiche sous forme de fenêtre.

Exemple de certificat de réussite
Exemple de certificat de réussite