前言
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]