Auf dieser Seite

Beispiel für eine fixierte Spalte

Dieses Beispiel zeigt, wie man eine Spalte innerhalb einer „ QTableView “ fixiert.

Anwendung, die eine fixierte Spalte in einer Tabelle anzeigt

Wir verwenden das Model-View-Framework von Qt, um eine Tabelle zu implementieren, bei der die erste Spalte fixiert ist. Diese Technik lässt sich auf mehrere Spalten oder Zeilen anwenden, solange diese sich am Rand der Tabelle befinden.

Das Model-View-Framework ermöglicht es, ein Modell mithilfe mehrerer Ansichten auf unterschiedliche Weise darzustellen. In diesem Beispiel verwenden wir zwei Ansichten für dasselbe Modell – zwei „ table views “, die sich ein Modell teilen. Die fixierte Spalte ist ein untergeordnetes Element der Haupt-TableView, und wir erzielen den gewünschten visuellen Effekt mithilfe einer Overlay-Technik, die in den folgenden Abschnitten Schritt für Schritt beschrieben wird.

Das Layout der Tabellenansicht, der Kopfzeilen und der Bildlaufleisten

Klassendefinition von `FreezeTableWidget`

Die Klasse „ FreezeTableWidget “ verfügt über einen Konstruktor und einen Destruktor. Außerdem hat sie zwei private Mitglieder: die Tabellenansicht, die wir als Overlay verwenden werden, und das gemeinsame Modell für beide Tabellenansichten. Es werden zwei Slots hinzugefügt, um die Größe der Abschnitte synchron zu halten, sowie eine Funktion zur Neuanpassung der Geometrie der eingefrorenen Spalte. Darüber hinaus implementieren wir zwei Funktionen neu: „ resizeEvent()“ und „ 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);

};

Hinweis: ` QAbstractItemView ` ist der Vorfahr von ` QTableView`.

Implementierung der Klasse `FreezeTableWidget`

Der Konstruktor nimmt „ model “ als Argument entgegen und erstellt eine Tabellenansicht, die wir zur Anzeige der fixierten Spalte verwenden werden. Anschließend rufen wir innerhalb des Konstruktors die Funktion „ init() “ auf, um die fixierte Spalte einzurichten. Schließlich verbinden wir die Signale „ QHeaderView::sectionResized()“ (für horizontale und vertikale Kopfzeilen) mit den entsprechenden Slots. Dadurch wird sichergestellt, dass die Abschnitte unserer fixierten Spalte mit den Kopfzeilen synchronisiert sind. Außerdem verbinden wir die vertikalen Bildlaufleisten miteinander, sodass die fixierte Spalte vertikal mit dem Rest unserer Tabelle mitläuft.

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);

}

In der Funktion ` init() ` stellen wir sicher, dass die Overlay-Tabellenansicht, die für die Anzeige der fixierten Spalte zuständig ist, korrekt eingerichtet ist. Das bedeutet, dass diese Tabellenansicht, ` frozenTableView`, dasselbe Modell wie die Haupttabellenansicht haben muss. Der Unterschied besteht hier jedoch darin, dass die einzige sichtbare Spalte von ` frozenTableView` die erste Spalte ist; die anderen blenden wir mit ` setColumnHidden()` aus.

void FreezeTableWidget::init()
{
      frozenTableView->setModel(model());
      frozenTableView->setFocusPolicy(Qt::NoFocus);
      frozenTableView->verticalHeader()->hide();
      frozenTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);

      viewport()->stackUnder(frozenTableView);

Was die Z-Reihenfolge der fixierten Spalte betrifft, ordnen wir sie über dem Viewport an. Dies erreichen wir durch den Aufruf von stackUnder() am Viewport. Aus optischen Gründen verhindern wir, dass die Spalte den Fokus von der Haupt-Tabellenansicht ablenkt. Außerdem stellen wir sicher, dass beide Ansichten dasselbe Auswahlmodell verwenden, sodass jeweils nur eine Zelle ausgewählt werden kann. Es werden noch einige weitere Anpassungen vorgenommen, damit unsere Anwendung gut aussieht und sich konsistent mit der Haupt-Tabellenansicht verhält. Beachten Sie, dass wir ` updateFrozenTableGeometry() ` aufgerufen haben, damit die Spalte die richtige Position einnimmt.

      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);
}

Wenn Sie die Größe der fixierten Spalte ändern, muss sich die entsprechende Spalte in der Haupt-Tabellenansicht entsprechend anpassen, um eine nahtlose Integration zu gewährleisten. Dies wird erreicht, indem die neue Größe der Spalte über den Wert „ newSize “ aus dem Signal „ sectionResized()“ abgerufen wird, das sowohl von der horizontalen als auch von der vertikalen Kopfzeile ausgesendet wird.

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);
}

Da die Breite der fixierten Spalte geändert wird, passen wir die Geometrie des Widgets entsprechend an, indem wir ` updateFrozenTableGeometry()` aufrufen. Diese Funktion wird weiter unten näher erläutert.

In unserer Neuimplementierung von ` QTableView::resizeEvent()` rufen wir ` updateFrozenTableGeometry() ` auf, nachdem wir die Implementierung der Basisklasse aufgerufen haben.

void FreezeTableWidget::resizeEvent(QResizeEvent * event)
{
      QTableView::resizeEvent(event);
      updateFrozenTableGeometry();
 }

Bei der Navigation in der Tabelle mit der Tastatur müssen wir sicherstellen, dass die aktuelle Auswahl nicht hinter der fixierten Spalte verschwindet. Um dies zu synchronisieren, implementieren wir ` QTableView::moveCursor()` neu und passen die Positionen der Bildlaufleisten bei Bedarf an, nachdem wir die Implementierung der Basisklasse aufgerufen haben.

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;
}

Die Geometrieberechnung der fixierten Spalte basiert auf der Geometrie der darunterliegenden Tabelle, sodass sie immer an der richtigen Stelle erscheint. Die Verwendung der Funktion ` QFrame::frameWidth()` hilft dabei, diese Geometrie korrekt zu berechnen, unabhängig davon, welcher Stil verwendet wird. Wir stützen uns auf die Geometrie des Ansichtsbereichs und der Kopfzeilen, um die Grenzen für die fixierte Spalte festzulegen.

void FreezeTableWidget::updateFrozenTableGeometry()
{
      frozenTableView->setGeometry(verticalHeader()->width() + frameWidth(),
                                   frameWidth(), columnWidth(0),
                                   viewport()->height()+horizontalHeader()->height());
}

Beispielprojekt @ code.qt.io

© 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.