Logo Spiria

Qt : des widgets dans l’en-tête des vues de listes

21 octobre 2021.

Il est souvent utile de pouvoir placer des widgets supplémentaires dans l’en-tête d’une liste ou d’un tableau Qt. Un exemple courant consiste à placer une coche dans l’en-tête pour activer ou désactiver une colonne en entier. Malheureusement, Qt 5 ne supporte pas cette fonctionnalité.

Une recherche rapide permettra de trouver quelques solutions, mais elles ont toutes des limitations. Par exemple, la solution décrite dans cette question de Stack Overflow ne prend en charge que les cases à cocher, et n’en supporte qu’une seule par table. Une autre solution proposée ne prend également en charge que les cases à cocher, mais constitue une bonne base de départ pour notre solution.

En nous inspirant de cette deuxième source, nous voulons améliorer la solution pour atteindre ces objectifs :

  • Supporter tout type de widget.
  • Supporter plusieurs colonnes, chacune ayant son propre widget.
  • Être simple à utiliser.

La solution

L’astuce consiste à avoir une vue d’en-tête personnalisée (QHeaderView) qui peut être définie sur une table (QTableWidget) ou une liste (QListWidget). La vue d’en-tête personnalisée prend en charge les widgets qui sont placés en haut de chaque colonne. Elle gère également l’emplacement et les changements de taille des widgets pour qu’ils s’intègrent à l’en-tête.

Étant donné que les widgets sont dessinés par-dessus l’en-tête, il est recommandé de ne pas définir de titre pour ces colonnes et d’utiliser plutôt un widget doté d’une étiquette. Puisque nous supportons tous les widgets, vous pouvez créer un conteneur pour placer une étiquette supplémentaire si le widget que vous souhaitez utiliser n’a pas d’étiquette.

L’astuce consistant à placer le widget par-dessus fonctionne parce que Qt peint les widgets parents avant leurs enfants. Comme les widgets supplémentaires sont des enfants de la vue d’en-tête, ils sont peints après l’en-tête et apparaissent donc au-dessus de celle-ci.

L’API permettant d’utiliser l’en-tête personnalisé est très simple. Il suffit de créer une instance de QHeaderViewWithWidgets, ajouter les widgets à la colonne (appelée section dans Qt), et définir la vue d’en-tête sur votre table. En bref, cela ressemble à ceci :

   // Creation du widget pour l'en-tete.
   auto col1_check = new QCheckBox("My checkbox");

   // Creation de l'en-tete avec le widget pour la colonne 1.
   auto header = new QHeaderViewWithWidgets(Qt::Orientation::Horizontal);
   header->addSectionWidget(1, col1_check);

   // Creation de la table et utilisation de l'en-tete.
   auto list = new QTableWidget;
   list->setHorizontalHeader(header);

Le code

Le code C++ nécessaire pour placer des widgets dans l'en-tête d'une table est disponible dans ce dépôt public sur GitHub.

Un exemple d'application utilisant la vue d'en-tête personnalisée avec des sous-widgets est fourni dans ce même projet, dans le dossier examples\ExampleListHeaderWidget.