前言
Qt编程-QTableView冻结行或冻结列或冻结局部单元格。如题,先看效果是不是你需要的。网上找到的代码片段要么不全要么不是想要的。如果你需要同时冻结行和列的效果,请看下篇博客 Qt编程-QTableView同时冻结行和列。
冻结列:
 
冻结行:
 
冻结局部单元格:
 
原理
冻结行或者冻结列原理: 使用2个tableview ,内容一样,上层tableview显示冻结的行或列 把非冻结的内容隐藏掉,下层tableview显示全部内容 下层tableview正常滑动就有冻结行或者列的效果了。
代码
代码改造来自 Qt自带例子 。可通过宏变量FREEZE_COL和FREEZE_ROW控制冻结行或冻结列。完整工程代码下载。
主要代码如下:
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 & 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:
      //冻结的行列数
      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 //冻结列开关
#define FREEZE_ROW 1 //冻结行开关
//! [constructor]
FreezeTableWidget::FreezeTableWidget(QAbstractItemModel * model)
{
      /*
冻结行或者冻结列原理:
实质上有2个tableview
            FreezeTableWidget继承QTableView 这个正常显示所有的表格数据
            FreezeTableWidget的成员变量frozenTableView 这个表格放在FreezeTableWidget的上面 只显示 冻结的行或者列 或者 你想显示的单元格,这样下面的 FreezeTableWidget 正常滑动就有冻结行或者列的效果了。
     */
      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);
      //LUpdate
      //冻结列,纵向滚动条可正常滑动
#if (FREEZE_COL && !FREEZE_ROW)
      connect(frozenTableView->verticalScrollBar(), &QAbstractSlider::valueChanged,
              verticalScrollBar(), &QAbstractSlider::setValue);
      connect(verticalScrollBar(), &QAbstractSlider::valueChanged,
              frozenTableView->verticalScrollBar(), &QAbstractSlider::setValue);
#endif
      //冻结行,横向滚动条可正常滑动
#if (!FREEZE_COL && FREEZE_ROW)
      connect(frozenTableView->horizontalScrollBar(), &QAbstractSlider::valueChanged,
              horizontalScrollBar(), &QAbstractSlider::setValue);
      connect(horizontalScrollBar(), &QAbstractSlider::valueChanged,
              frozenTableView->horizontalScrollBar(), &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
      //隐藏冻结列以外的数据
      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
      //隐藏冻结行以外的行的数据
      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 && 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);
      }
#endif
#if FREEZE_ROW
      if(cursorAction == MoveDown && current.row() > 0
              && 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 & 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]
                ![[stm32]外中断控制灯光](https://img-blog.csdnimg.cn/17e739abf95f441098635e1722631807.png)


![2023年中国助消化药物行业现状分析:消化不良患者逐年上升,提升需求量[图]](https://img-blog.csdnimg.cn/img_convert/25439f200d470dba0ea0f58f272ab4c8.png)




![[spring] spring jpa - hibernate 名词解释配置](https://img-blog.csdnimg.cn/4abf4644d30f4d5c9b307bf549faa34c.png)










