Foreword
Qt Programming-QTableView freezes rows or columns or freezes partial cells. Like the title, first check if the effect is what you need. The code snippets found online are either incomplete or not what you want. If you need the effect of freezing rows and columns at the same time, please read the next blog Qt programming-QTableView freezes rows and columns at the same time.
Freeze columns:
Freeze rows:
Freeze local cells:
Principle
Principle of freezing rows or columns: Use two tableviews with the same content. The upper tableview displays the frozen rows or columns, hides the non-frozen content, and the lower tableview displays all the content. The lower tableview slides normally to have the effect of freezing rows or columns.
Code
The code transformation comes from Qt’s own examples. Freeze rows or columns can be controlled through the macro variables FREEZE_COL and FREEZE_ROW. Download the complete project code.
The main code is as follows:
freezetablewidget.h
#ifndef FREEZETABLEWIDGET_H #define FREEZETABLEWIDGET_H #include <QTableView> //! [Widget definition] 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 & amp; 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); private: //The number of frozen rows and columns int m_iFreezeCols = 3; int m_iFreezeRows = 3; }; //! [Widget definition] #endif // FREEZETABLEWIDGET_H
freezetablewidget.cpp
#include "freezetablewidget.h" #include <QScrollBar> #include <QHeaderView> #include <QDebug> #define FREEZE_COL 1 //Freeze column switch #define FREEZE_ROW 1 //Freeze row switch //! [constructor] FreezeTableWidget::FreezeTableWidget(QAbstractItemModel * model) { /* Principle of freezing rows or columns: Essentially there are 2 tableviews FreezeTableWidget inherits QTableView and displays all table data normally. The member variable frozenTableView of FreezeTableWidget is placed on top of FreezeTableWidget to only display the frozen rows or columns or the cells you want to display, so that the FreezeTableWidget below will have the effect of freezing rows or columns when sliding normally. */ setModel(model); frozenTableView = new QTableView(this); init(); //connect the headers and scrollbars of both tableviews together connect(horizontalHeader(), & amp;QHeaderView::sectionResized, this, & amp;FreezeTableWidget::updateSectionWidth); connect(verticalHeader(), & amp;QHeaderView::sectionResized, this, & amp;FreezeTableWidget::updateSectionHeight); //LUpdate //Freeze the column and the vertical scroll bar can slide normally #if (FREEZE_COL & amp; & amp; !FREEZE_ROW) connect(frozenTableView->verticalScrollBar(), & amp;QAbstractSlider::valueChanged, verticalScrollBar(), & amp;QAbstractSlider::setValue); connect(verticalScrollBar(), & amp;QAbstractSlider::valueChanged, frozenTableView->verticalScrollBar(), & amp;QAbstractSlider::setValue); #endif //Freeze the row and the horizontal scroll bar can slide normally #if (!FREEZE_COL & amp; & amp; FREEZE_ROW) connect(frozenTableView->horizontalScrollBar(), & amp;QAbstractSlider::valueChanged, horizontalScrollBar(), & amp;QAbstractSlider::setValue); connect(horizontalScrollBar(), & amp;QAbstractSlider::valueChanged, frozenTableView->horizontalScrollBar(), & amp;QAbstractSlider::setValue); #endif } //! [constructor] FreezeTableWidget::~FreezeTableWidget() { delete frozenTableView; } //! [init part1] void FreezeTableWidget::init() { frozenTableView->setModel(model()); frozenTableView->setFocusPolicy(Qt::NoFocus); frozenTableView->verticalHeader()->setFixedWidth(verticalHeader()->width()); frozenTableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); frozenTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed); viewport()->stackUnder(frozenTableView); //! [init part1] //! [init part2] frozenTableView->setStyleSheet("QTableView { border: none;" "background-color: #8EDE21;" "selection-background-color: #999}"); //for demo purposes frozenTableView->setSelectionModel(selectionModel()); //LUpdate #if FREEZE_COL //Hide data other than frozen columns for (int col = m_iFreezeCols; col < model()->columnCount(); + + col) frozenTableView->setColumnHidden(col, true); for(int i = 0; i < m_iFreezeCols; i + + ) { frozenTableView->setColumnWidth(i, columnWidth(0)); } #endif #if FREEZE_ROW //Hide data in rows other than frozen rows for (int row = m_iFreezeRows; row < model()->rowCount(); + + row) frozenTableView->setRowHidden(row, true); for(int i = 0; i < m_iFreezeRows; i + + ) { frozenTableView->setRowHeight(i, rowHeight(0)); } #endif frozenTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); frozenTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); frozenTableView->show(); updateFrozenTableGeometry(); setHorizontalScrollMode(ScrollPerPixel); setVerticalScrollMode(ScrollPerPixel); frozenTableView->setVerticalScrollMode(ScrollPerPixel); frozenTableView->setHorizontalScrollMode(ScrollPerPixel); } //! [init part2] //! [sections] void FreezeTableWidget::updateSectionWidth(int logicalIndex, int /* oldSize */, int newSize) { qDebug() << "updateSectionWidth" << logicalIndex << newSize; //LUpdate #if FREEZE_COL if (logicalIndex == m_iFreezeCols-1){ int width = 0; for(int i = 0; i< m_iFreezeCols-1; i + + ) { width + = columnWidth(i); } for(int i = 0; i< m_iFreezeCols; i + + ) { frozenTableView->setColumnWidth(i, (newSize + width)/m_iFreezeCols); } updateFrozenTableGeometry(); } #else frozenTableView->setColumnWidth(logicalIndex, newSize); #endif } void FreezeTableWidget::updateSectionHeight(int logicalIndex, int /* oldSize */, int newSize) { qDebug() << "updateSectionHeight" << logicalIndex << newSize; //LUpdate #if FREEZE_ROW if (logicalIndex == m_iFreezeRows-1){ int height = 0; for(int i = 0; i< m_iFreezeRows-1; i + + ) { height + = rowHeight(i); } for(int i = 0; i< m_iFreezeRows; i + + ) { frozenTableView->setRowHeight(i, (newSize + height)/m_iFreezeRows); } updateFrozenTableGeometry(); } #else frozenTableView->setRowHeight(logicalIndex, newSize); #endif } //! [sections] //! [resize] void FreezeTableWidget::resizeEvent(QResizeEvent * event) { QTableView::resizeEvent(event); updateFrozenTableGeometry(); } //! [resize] //! [navigate] QModelIndex FreezeTableWidget::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) { QModelIndex current = QTableView::moveCursor(cursorAction, modifiers); #if FREEZE_COL if (cursorAction == MoveLeft & amp; & amp; current.column() > 0 & amp; & amp; visualRect(current).topLeft().x() < frozenTableView->columnWidth(0) ){ const int newValue = horizontalScrollBar()->value() + visualRect(current).topLeft().x() - frozenTableView->columnWidth(0); horizontalScrollBar()->setValue(newValue); } #endif #if FREEZE_ROW if(cursorAction == MoveDown & amp; & amp; current.row() > 0 & amp; & amp; visualRect(current).topLeft().y() < frozenTableView->rowHeight(0)) { const int newValue = verticalScrollBar()->value() + visualRect(current).topLeft().y() - frozenTableView->rowHeight(0); verticalScrollBar()->setValue(newValue); } #endif return current; } //! [navigate] void FreezeTableWidget::scrollTo (const QModelIndex & amp; index, ScrollHint hint){ if (index.column() > 0) QTableView::scrollTo(index, hint); } //! [geometry] void FreezeTableWidget::updateFrozenTableGeometry() { //LUpdate int width = 0, height = 0, x = 0, y = 0; qDebug() << "ver:" << verticalHeader()->width() << verticalHeader()->height(); qDebug() << "hor:" << horizontalHeader()->width() << horizontalHeader()->height(); qDebug() << "frame:" << frameWidth() << frameRect().width()<< frameRect().height() << frameRect().x() << frameRect().y (); x = frameWidth(); y = frameWidth(); #if FREEZE_COL width = verticalHeader()->width(); for(int i = 0; i< m_iFreezeCols; i + + ) { width + = columnWidth(i); } #else width = viewport()->width() + verticalHeader()->width(); #endif #if FREEZE_ROW height = horizontalHeader()->height(); for(int i = 0; i< m_iFreezeRows; i + + ) { height + = rowHeight(i); } #else height = viewport()->height() + horizontalHeader()->height(); #endif qDebug() << "x, y, width, height" << x << y << width << height; frozenTableView->setGeometry(x, y, width, height); } //! [geometry]