前言
Qt编程-QTableView同时冻结行和列。如题,先看效果是不是你需要的。网上找到的代码片段要么不全要么不是想要的。如果你只需要需要冻结行或冻结列,请看上篇博客 Qt编程-QTableView冻结行或冻结列或冻结局部单元格 ,代码更少一些。
同时冻结行列带表头:
同时冻结行列不带表头:
原理
冻结行或者冻结列原理: 使用3个tableview ,内容一样,最上层tableview显示交叉部分内容,中间层显示冻结的行tableview和冻结列tableview 把非冻结的内容隐藏掉,下层显示全部内容 下层tableview正常滑动就有冻结行或者列的效果了。
代码
代码改造来自 Qt自带例子 。可通过宏变量FREEZE_COL和FREEZE_ROW控制冻结行或冻结列,宏变量TABLE_HEAD控制表头显示。完整工程代码下载。
主要代码如下:
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 *frozenCroTableView; //冻结行冻结列交叉部分的TableView
QTableView *frozenColTableView; //冻结列的TableView
QTableView *frozenRowTableView; //冻结行的TableView
void initCroTable();
void initColTable();
void initRowTable();
void updateFrozenCroTableGeometry();
void updateFrozenColTableGeometry();
void updateFrozenRowTableGeometry();
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 //冻结行开关
#define TABLE_HEAD 0 //表头是否显示
//! [constructor]
FreezeTableWidget::FreezeTableWidget(QAbstractItemModel * model)
{
/*
冻结行或者冻结列 原理:实质上有2个tableview
FreezeTableWidget 这个正常显示所有的表格数据
frozenColTableView 这个表格放在FreezeTableWidget的上面 只显示 冻结的列,这样下面的 FreezeTableWidget 正常滑动就有冻结列的效果了。
同时冻结行列 原理类似,不过是3个tableview,冻结行和冻结列的tableview交叉部分单独作为一个tableview要放在最顶层,下面是冻结行和冻结列的tableview 最下面是 FreezeTableWidget的tableview。
*/
verticalHeader()->setVisible(TABLE_HEAD);
horizontalHeader()->setVisible(TABLE_HEAD);
setModel(model);
#if (FREEZE_COL && FREEZE_ROW)
frozenCroTableView = new QTableView(this);
initCroTable();
#endif
#if FREEZE_COL
frozenColTableView = new QTableView(this);
initColTable();
#endif
#if FREEZE_ROW
frozenRowTableView = new QTableView(this);
initRowTable();
#endif
//connect the headers and scrollbars of both tableviews together
#if FREEZE_COL
connect(horizontalHeader(),&QHeaderView::sectionResized, this,
&FreezeTableWidget::updateSectionWidth);
#endif
#if FREEZE_ROW
connect(verticalHeader(),&QHeaderView::sectionResized, this,
&FreezeTableWidget::updateSectionHeight);
#endif
//LUpdate
//冻结列,纵向滚动条可正常滑动
#if FREEZE_COL
connect(frozenColTableView->verticalScrollBar(), &QAbstractSlider::valueChanged,
verticalScrollBar(), &QAbstractSlider::setValue);
connect(verticalScrollBar(), &QAbstractSlider::valueChanged,
frozenColTableView->verticalScrollBar(), &QAbstractSlider::setValue);
#endif
//冻结行,横向向滚动条可正常滑动
#if FREEZE_ROW
connect(frozenRowTableView->horizontalScrollBar(), &QAbstractSlider::valueChanged,
horizontalScrollBar(), &QAbstractSlider::setValue);
connect(horizontalScrollBar(), &QAbstractSlider::valueChanged,
frozenRowTableView->horizontalScrollBar(), &QAbstractSlider::setValue);
#endif
}
//! [constructor]
FreezeTableWidget::~FreezeTableWidget()
{
#if FREEZE_COL
delete frozenColTableView;
#endif
#if FREEZE_ROW
delete frozenRowTableView;
#endif
#if FREEZE_COL && FREEZE_ROW
delete frozenCroTableView;
#endif
}
//! [init part1]
void FreezeTableWidget::initCroTable()
{
frozenCroTableView->setModel(model());
frozenCroTableView->setObjectName("frozenCroTableView");
frozenCroTableView->setFocusPolicy(Qt::NoFocus);
frozenCroTableView->verticalHeader()->setFixedWidth(verticalHeader()->width());
frozenCroTableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
frozenCroTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
#if !TABLE_HEAD
frozenCroTableView->horizontalHeader()->hide();
frozenCroTableView->verticalHeader()->hide();
#endif
viewport()->stackUnder(frozenCroTableView);
//! [init part1]
//! [init part2]
frozenCroTableView->setStyleSheet("#frozenCroTableView{ border: none;"
"background-color: #AEC8FF;"
"selection-background-color: #999}"); //for demo purposes
frozenCroTableView->setSelectionModel(selectionModel());
//LUpdate
//隐藏冻结列以外的数据
for (int col = m_iFreezeCols; col < model()->columnCount(); ++col)
frozenCroTableView->setColumnHidden(col, true);
for(int i = 0; i < m_iFreezeCols; i++)
{
frozenCroTableView->setColumnWidth(i, columnWidth(0));
}
//隐藏冻结行以外的行的数据
for (int row = m_iFreezeRows; row < model()->rowCount(); ++row)
frozenCroTableView->setRowHidden(row, true);
for(int i = 0; i < m_iFreezeRows; i++)
{
frozenCroTableView->setRowHeight(i, rowHeight(0));
}
frozenCroTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
frozenCroTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
frozenCroTableView->show();
updateFrozenCroTableGeometry();
setHorizontalScrollMode(ScrollPerPixel);
setVerticalScrollMode(ScrollPerPixel);
frozenCroTableView->setVerticalScrollMode(ScrollPerPixel);
frozenCroTableView->setHorizontalScrollMode(ScrollPerPixel);
}
//! [init part1]
void FreezeTableWidget::initColTable()
{
frozenColTableView->setModel(model());
frozenColTableView->setObjectName("frozenColTableView");
frozenColTableView->setFocusPolicy(Qt::NoFocus);
frozenColTableView->verticalHeader()->setFixedWidth(verticalHeader()->width());
frozenColTableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
frozenColTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
#if !TABLE_HEAD
frozenColTableView->horizontalHeader()->hide();
frozenColTableView->verticalHeader()->hide();
#endif
#if FREEZE_COL && FREEZE_ROW
frozenColTableView->stackUnder(frozenCroTableView);
#else
viewport()->stackUnder(frozenColTableView);
#endif
//! [init part1]
//! [init part2]
frozenColTableView->setStyleSheet("#frozenColTableView{ border: none;"
"background-color: #8EDE21;"
"selection-background-color: #999}"); //for demo purposes
frozenColTableView->setSelectionModel(selectionModel());
//LUpdate
//隐藏冻结列以外的数据
for (int col = m_iFreezeCols; col < model()->columnCount(); ++col)
frozenColTableView->setColumnHidden(col, true);
for(int i = 0; i < m_iFreezeCols; i++)
{
frozenColTableView->setColumnWidth(i, columnWidth(0));
}
frozenColTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
frozenColTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
frozenColTableView->show();
updateFrozenColTableGeometry();
setHorizontalScrollMode(ScrollPerPixel);
setVerticalScrollMode(ScrollPerPixel);
frozenColTableView->setVerticalScrollMode(ScrollPerPixel);
frozenColTableView->setHorizontalScrollMode(ScrollPerPixel);
}
void FreezeTableWidget::initRowTable()
{
frozenRowTableView->setModel(model());
frozenRowTableView->setObjectName("frozenRowTableView");
frozenRowTableView->setFocusPolicy(Qt::NoFocus);
frozenRowTableView->verticalHeader()->setFixedWidth(verticalHeader()->width());
frozenRowTableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
frozenRowTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
#if !TABLE_HEAD
frozenRowTableView->horizontalHeader()->hide();
frozenRowTableView->verticalHeader()->hide();
#endif
#if FREEZE_COL
frozenRowTableView->stackUnder(frozenColTableView);
#else
viewport()->stackUnder(frozenRowTableView);
#endif
//! [init part1]
//! [init part2]
frozenRowTableView->setStyleSheet("#frozenRowTableView{ border: none;"
"background-color: #f44c46;"
"selection-background-color: #999}"); //for demo purposes
frozenRowTableView->setSelectionModel(selectionModel());
//LUpdate
//隐藏冻结行以外的行的数据
for (int row = m_iFreezeRows; row < model()->rowCount(); ++row)
frozenRowTableView->setRowHidden(row, true);
for(int i = 0; i < m_iFreezeRows; i++)
{
frozenRowTableView->setRowHeight(i, rowHeight(0));
}
frozenRowTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
frozenRowTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
frozenRowTableView->show();
updateFrozenRowTableGeometry();
setHorizontalScrollMode(ScrollPerPixel);
setVerticalScrollMode(ScrollPerPixel);
frozenRowTableView->setVerticalScrollMode(ScrollPerPixel);
frozenRowTableView->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++)
{
frozenColTableView->setColumnWidth(i, (newSize+width)/m_iFreezeCols);
}
updateFrozenColTableGeometry();
}
#else
frozenColTableView->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++)
{
frozenRowTableView->setRowHeight(i, (newSize+height)/m_iFreezeRows);
}
updateFrozenRowTableGeometry();
}
#else
frozenRowTableView->setRowHeight(logicalIndex, newSize);
#endif
}
//! [sections]
//! [resize]
void FreezeTableWidget::resizeEvent(QResizeEvent * event)
{
QTableView::resizeEvent(event);
#if FREEZE_COL
updateFrozenColTableGeometry();
#endif
#if FREEZE_ROW
updateFrozenRowTableGeometry();
#endif
#if FREEZE_ROW && FREEZE_COL
updateFrozenCroTableGeometry();
#endif
}
//! [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() < frozenColTableView->columnWidth(0) ){
const int newValue = horizontalScrollBar()->value() + visualRect(current).topLeft().x()
- frozenColTableView->columnWidth(0);
horizontalScrollBar()->setValue(newValue);
}
#endif
#if FREEZE_ROW
if(cursorAction == MoveDown && current.row() > 0
&& visualRect(current).topLeft().y() < frozenRowTableView->rowHeight(0))
{
const int newValue = verticalScrollBar()->value() + visualRect(current).topLeft().y()
- frozenRowTableView->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::updateFrozenCroTableGeometry()
{
qDebug() << "updateFrozenCroTableGeometry ==";
//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 && FREEZE_ROW
width = verticalHeader()->width();
for(int i = 0; i< m_iFreezeCols; i++)
{
width += columnWidth(i);
}
height = horizontalHeader()->height();
for(int i = 0; i< m_iFreezeRows; i++)
{
height += rowHeight(i);
}
#else
width = viewport()->width()+verticalHeader()->width();
height = viewport()->height()+horizontalHeader()->height();
#endif
qDebug() << "x, y, width, height" << x << y << width << height;
frozenCroTableView->setGeometry(x, y, width, height);
}
//! [geometry]
//! [geometry]
void FreezeTableWidget::updateFrozenColTableGeometry()
{
qDebug() << "updateFrozenColTableGeometry ==";
//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
height = viewport()->height()+horizontalHeader()->height();
qDebug() << "x, y, width, height" << x << y << width << height;
frozenColTableView->setGeometry(x, y, width, height);
}
//! [geometry]
//! [geometry]
void FreezeTableWidget::updateFrozenRowTableGeometry()
{
qDebug() << "updateFrozenRowTableGeometry ==";
//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();
width = viewport()->width()+verticalHeader()->width();
#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;
frozenRowTableView->setGeometry(x, y, width, height);
}
//! [geometry]