Exemple de colonne figée
Cet exemple montre comment figer une colonne dans un tableau QTableView.

Nous utilisons le framework modèle/vue de Qt pour implémenter un tableau dont la première colonne est figée. Cette technique peut être appliquée à plusieurs colonnes ou lignes, à condition qu'elles se trouvent sur le bord du tableau.
Le framework modèle/vue permet d’afficher un même modèle de différentes manières à l’aide de plusieurs vues. Pour cet exemple, nous utilisons deux vues sur le même modèle : deux objets ` table views ` partageant un même modèle. La colonne figée est un enfant de la vue de tableau principale, et nous obtenons l’effet visuel souhaité à l’aide d’une technique de superposition qui sera décrite étape par étape dans les sections suivantes.

Définition de la classe `FreezeTableWidget`
La classe d’ FreezeTableWidget dispose d’un constructeur et d’un destructeur. Elle comporte également deux membres privés : la table view que nous utiliserons comme superposition, et le modèle partagé par les deux table views. Deux slots sont ajoutés pour aider à synchroniser la taille des sections, ainsi qu’une fonction permettant de réajuster la géométrie de la colonne figée. De plus, nous réimplémentons deux fonctions : ` resizeEvent()` et ` moveCursor()`.
class FreezeTableWidget : public QTableView {
Q_OBJECT
public:
FreezeTableWidget(QAbstractItemModel * model);
~FreezeTableWidget();
protected:
void resizeEvent(QResizeEvent *event) override;
QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
void scrollTo (const QModelIndex & index, ScrollHint hint = EnsureVisible) override;
private:
QTableView *frozenTableView;
void init();
void updateFrozenTableGeometry();
private slots:
void updateSectionWidth(int logicalIndex, int oldSize, int newSize);
void updateSectionHeight(int logicalIndex, int oldSize, int newSize);
};Remarque : ` QAbstractItemView ` est l’ancêtre de ` QTableView`.
Implémentation de la classe `FreezeTableWidget`
Le constructeur prend model en argument et crée une vue de tableau que nous utiliserons pour afficher la colonne figée. Ensuite, au sein du constructeur, nous appelons la fonction init() pour configurer la colonne figée. Enfin, nous connectons les signaux ` QHeaderView::sectionResized()` (pour les en-têtes horizontaux et verticaux) aux slots appropriés. Cela garantit que les sections de notre colonne figée sont synchronisées avec les en-têtes. Nous connectons également les barres de défilement verticales entre elles afin que la colonne figée défile verticalement avec le reste de notre tableau.
FreezeTableWidget::FreezeTableWidget(QAbstractItemModel * model)
{
setModel(model);
frozenTableView = new QTableView(this);
init();
//connect the headers and scrollbars of both tableviews together
connect(horizontalHeader(),&QHeaderView::sectionResized, this,
&FreezeTableWidget::updateSectionWidth);
connect(verticalHeader(),&QHeaderView::sectionResized, this,
&FreezeTableWidget::updateSectionHeight);
connect(frozenTableView->verticalScrollBar(), &QAbstractSlider::valueChanged,
verticalScrollBar(), &QAbstractSlider::setValue);
connect(verticalScrollBar(), &QAbstractSlider::valueChanged,
frozenTableView->verticalScrollBar(), &QAbstractSlider::setValue);
}Dans la fonction ` init() `, nous nous assurons que la vue de tableau superposée chargée d’afficher la colonne figée est correctement configurée. Cela signifie que cette vue de tableau, ` frozenTableView`, doit avoir le même modèle que la vue de tableau principale. Cependant, la différence ici est la suivante : la seule colonne visible de ` frozenTableView` est sa première colonne ; nous masquons les autres à l’aide de ` setColumnHidden()`.
void FreezeTableWidget::init()
{
frozenTableView->setModel(model());
frozenTableView->setFocusPolicy(Qt::NoFocus);
frozenTableView->verticalHeader()->hide();
frozenTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
viewport()->stackUnder(frozenTableView);En ce qui concerne l’ordre de superposition de la colonne figée, nous la plaçons au-dessus de la fenêtre d’affichage. Pour ce faire, nous appelons la méthode stackUnder() sur la fenêtre d’affichage. Pour des raisons esthétiques, nous empêchons la colonne de détourner l’attention de la vue de tableau principale. De plus, nous veillons à ce que les deux vues partagent le même modèle de sélection, afin qu’une seule cellule puisse être sélectionnée à la fois. Quelques autres ajustements sont effectués pour que notre application soit esthétique et se comporte de manière cohérente avec la tableView principale. Notez que nous avons appelé ` updateFrozenTableGeometry() ` pour que la colonne occupe la bonne position.
frozenTableView->setStyleSheet("QTableView { border: none;"
"background-color: #8EDE21;"
"selection-background-color: #999}"); //for demo purposes
frozenTableView->setSelectionModel(selectionModel());
for (int col = 1; col < model()->columnCount(); ++col)
frozenTableView->setColumnHidden(col, true);
frozenTableView->setColumnWidth(0, columnWidth(0) );
frozenTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
frozenTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
frozenTableView->show();
updateFrozenTableGeometry();
setHorizontalScrollMode(ScrollPerPixel);
setVerticalScrollMode(ScrollPerPixel);
frozenTableView->setVerticalScrollMode(ScrollPerPixel);
}Lorsque vous redimensionnez la colonne figée, la colonne correspondante de la vue de table principale doit s’adapter en conséquence, afin d’assurer une intégration transparente. Pour ce faire, nous récupérons la nouvelle taille de la colonne à partir de la valeur « newSize » du signal « sectionResized() », émis à la fois par l’en-tête horizontale et l’en-tête verticale.
void FreezeTableWidget::updateSectionWidth(int logicalIndex, int /* oldSize */, int newSize)
{
if (logicalIndex == 0){
frozenTableView->setColumnWidth(0, newSize);
updateFrozenTableGeometry();
}
}
void FreezeTableWidget::updateSectionHeight(int logicalIndex, int /* oldSize */, int newSize)
{
frozenTableView->setRowHeight(logicalIndex, newSize);
}La largeur de la colonne figée étant modifiée, nous ajustons la géométrie du widget en conséquence en appelant la fonction ` updateFrozenTableGeometry()`. Cette fonction est expliquée plus en détail ci-dessous.
Dans notre réimplémentation de ` QTableView::resizeEvent()`, nous appelons ` updateFrozenTableGeometry() ` après avoir invoqué l’implémentation de la classe de base.
void FreezeTableWidget::resizeEvent(QResizeEvent * event)
{
QTableView::resizeEvent(event);
updateFrozenTableGeometry();
}Lors de la navigation dans le tableau à l’aide du clavier, nous devons nous assurer que la sélection actuelle ne disparaît pas derrière la colonne figée. Pour synchroniser cela, nous réimplémentons ` QTableView::moveCursor()` et ajustons les positions des barres de défilement si nécessaire, après avoir appelé l’implémentation de la classe de base.
QModelIndex FreezeTableWidget::moveCursor(CursorAction cursorAction,
Qt::KeyboardModifiers modifiers)
{
QModelIndex current = QTableView::moveCursor(cursorAction, modifiers);
if (cursorAction == MoveLeft && current.column() > 0
&& visualRect(current).topLeft().x() < frozenTableView->columnWidth(0) ){
const int newValue = horizontalScrollBar()->value() + visualRect(current).topLeft().x()
- frozenTableView->columnWidth(0);
horizontalScrollBar()->setValue(newValue);
}
return current;
}Le calcul de la géométrie de la colonne figée repose sur celle du tableau sous-jacent, ce qui garantit qu’elle s’affiche toujours au bon endroit. L’utilisation de la fonction QFrame::frameWidth() permet de calculer correctement cette géométrie, quel que soit le style utilisé. Nous nous appuyons sur la géométrie de la fenêtre d’affichage et des en-têtes pour définir les limites de la colonne figée.
void FreezeTableWidget::updateFrozenTableGeometry()
{
frozenTableView->setGeometry(verticalHeader()->width() + frameWidth(),
frameWidth(), columnWidth(0),
viewport()->height()+horizontalHeader()->height());
}© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.