主要参考Qt 示例 frozencolumn,该实例功能为固定左侧两列,在此基础上实现了左右两侧部分列固定功能。
#ifndef FREEZETABLEWIDGET_H
#define FREEZETABLEWIDGET_H
#include <QTableView>
//! [Widget definition]
class FreezeTableWidget : public QTableView {
Q_OBJECT
public:
explicit FreezeTableWidget(QWidget *parent = nullptr);
~FreezeTableWidget();
void SetColumnFreezeLeft(int nCol = 0);
void SetColumnFreezeRight(int nCol = 0);
void SetModel(QAbstractItemModel * model);
protected:
void resizeEvent(QResizeEvent *event) override;
void scrollTo(const QModelIndex & index, ScrollHint hint = EnsureVisible) override;
QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
private:
void init();
void initUI();
void initTableUI(QTableView *TableView, QString& strStyleSheet);
void updateFrozenTableGeometry();
private slots:
void updateSectionWidth(int logicalIndex, int oldSize, int newSize);
void updateSectionHeight(int logicalIndex, int oldSize, int newSize);
private:
QTableView *m_FrozenTableViewLeft;
QTableView *m_FrozenTableViewRight;
int m_nFreezeColumnLeft;
int m_nFreezeColumnRight;
QString m_strStyleSheet;
};
//! [Widget definition]
#endif // FREEZETABLEWIDGET_H
#include "freezetablewidget.h"
#include <QScrollBar>
#include <QHeaderView>
//! [constructor]
FreezeTableWidget::FreezeTableWidget(QWidget *parent /*= nullptr*/)
: m_nFreezeColumnLeft(0)
, m_nFreezeColumnRight(0)
{
setParent(parent);
m_FrozenTableViewLeft = new QTableView(this);
m_FrozenTableViewRight = new QTableView(this);
m_strStyleSheet = QString::fromUtf8("QTableView{\n"
" background:#1d1b23;\n"
" outline:0px;\n"
" font-size:9pt;\n"
" border: 0px;\n"
"}\n"
"\n"
"QHeaderView::section{\n"
" text-align:center;\n"
" background:#1d1b23;\n"
" height:60px;\n"
" margin:0px;\n"
" font-size:9pt;\n"
" color:#ffffff;\n"
" border:none;\n"
" border-bottom:1px solid #333333;\n"
"}\n"
"\n"
"QTableView::item{\n"
" color:white;\n"
" outline:0px;\n"
" height:60px;\n"
" border-bottom:1px solid #333333;\n"
"}\n"
"QTableView::item:selected{\n"
" border:0;\n"
" outline:0px; \n"
" background:#2a9d8f;\n"
"}");
this->setStyleSheet(m_strStyleSheet); // 初始化背景
m_FrozenTableViewLeft->hide();
m_FrozenTableViewRight->hide();
QString leftRightHeaderStyle = "QHeaderView::section{text-align:center;background:#1f2c31;height:60px;"
" margin:0px;font-size:9pt;color:#ffffff;border:none;border-bottom:1px solid #333333;}";
m_FrozenTableViewLeft->setStyleSheet(leftRightHeaderStyle);
m_FrozenTableViewRight->setStyleSheet(leftRightHeaderStyle);
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(m_FrozenTableViewLeft->verticalScrollBar(), &QAbstractSlider::valueChanged,
verticalScrollBar(), &QAbstractSlider::setValue);
connect(verticalScrollBar(), &QAbstractSlider::valueChanged,
m_FrozenTableViewLeft->verticalScrollBar(), &QAbstractSlider::setValue);
connect(m_FrozenTableViewRight->verticalScrollBar(), &QAbstractSlider::valueChanged,
verticalScrollBar(), &QAbstractSlider::setValue);
connect(verticalScrollBar(), &QAbstractSlider::valueChanged,
m_FrozenTableViewRight->verticalScrollBar(), &QAbstractSlider::setValue);
}
//! [constructor]
FreezeTableWidget::~FreezeTableWidget()
{
if (m_FrozenTableViewLeft != nullptr)
{
delete m_FrozenTableViewLeft;
m_FrozenTableViewLeft = nullptr;
}
if (m_FrozenTableViewRight != nullptr)
{
delete m_FrozenTableViewRight;
m_FrozenTableViewRight = nullptr;
}
}
void FreezeTableWidget::SetColumnFreezeLeft(int nCol /*= 0*/)
{
m_nFreezeColumnLeft = nCol;
}
void FreezeTableWidget::SetColumnFreezeRight(int nCol /*= 0*/)
{
m_nFreezeColumnRight = nCol;
}
void FreezeTableWidget::SetModel(QAbstractItemModel * theModel)
{
setModel(theModel);
m_FrozenTableViewLeft->setModel(theModel);
m_FrozenTableViewRight->setModel(theModel);
initUI();
}
void FreezeTableWidget::init()
{
this->setShowGrid(false);
this->verticalHeader()->hide();
this->setEditTriggers(NoEditTriggers);
this->setSelectionBehavior(QAbstractItemView::SelectRows);
this->viewport()->stackUnder(m_FrozenTableViewLeft); // 只能设置一个
this->setHorizontalScrollMode(ScrollPerPixel);
this->setVerticalScrollMode(ScrollPerPixel);
this->verticalHeader()->setDefaultSectionSize(50);
}
void FreezeTableWidget::initUI()
{
int nColCnt = model()->columnCount();
if (nColCnt < m_nFreezeColumnLeft || nColCnt < m_nFreezeColumnRight)
{
return;
}
QString strStyleSheet = QString(
"QTableView { border: none;"
"background-color: #1d1b23;"
"selection-background-color: #999}"
"QHeaderView::section{text-align:center;background:#1f2c31;height:60px;"
" margin:0px;font-size:9pt;color:#ffffff;border:none;border-bottom:1px solid #333333;}"
);
initTableUI(m_FrozenTableViewLeft, strStyleSheet);
initTableUI(m_FrozenTableViewRight, strStyleSheet);
for (int col = m_nFreezeColumnLeft; col < model()->columnCount(); ++col)
m_FrozenTableViewLeft->setColumnHidden(col, true);
for (int i = 0; i < m_nFreezeColumnLeft; ++i)
{
m_FrozenTableViewLeft->setColumnWidth(i, columnWidth(i));
}
for (int col = 0; col < model()->columnCount() - m_nFreezeColumnRight; ++col)
m_FrozenTableViewRight->setColumnHidden(col, true);
for (int i = model()->columnCount() - m_nFreezeColumnRight; i < model()->columnCount(); ++i)
{
m_FrozenTableViewRight->setColumnWidth(i, columnWidth(i));
}
updateFrozenTableGeometry();
}
void FreezeTableWidget::initTableUI(QTableView *TableView, QString& strStyleSheet)
{
TableView->setStyleSheet(strStyleSheet);
TableView->setFocusPolicy(Qt::NoFocus);
TableView->verticalHeader()->hide();
TableView->verticalHeader()->setDefaultSectionSize(50);
TableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
TableView->horizontalHeader()->setFixedHeight(horizontalHeader()->height());
TableView->setSelectionModel(selectionModel());
TableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
TableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
TableView->setVerticalScrollMode(ScrollPerPixel);
TableView->setEditTriggers(NoEditTriggers);
TableView->setSelectionBehavior(QAbstractItemView::SelectRows);
TableView->setShowGrid(false);
TableView->show();
}
//! [sections]
void FreezeTableWidget::updateSectionWidth(int logicalIndex, int /* oldSize */, int newSize)
{
if (logicalIndex == 0)
{
m_FrozenTableViewLeft->setColumnWidth(0, newSize);
updateFrozenTableGeometry();
}
}
void FreezeTableWidget::updateSectionHeight(int logicalIndex, int /* oldSize */, int newSize)
{
m_FrozenTableViewLeft->setRowHeight(logicalIndex, newSize);
m_FrozenTableViewRight->setRowHeight(logicalIndex, newSize);
}
//! [sections]
//! [resize]
void FreezeTableWidget::resizeEvent(QResizeEvent * event)
{
QTableView::resizeEvent(event);
if (model() != nullptr)
{
updateFrozenTableGeometry();
}
}
//! [resize]
//! [navigate]
QModelIndex FreezeTableWidget::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
{
QModelIndex current = QTableView::moveCursor(cursorAction, modifiers);
if (cursorAction == MoveLeft && current.column() > 0
&& visualRect(current).topLeft().x() < m_FrozenTableViewLeft->columnWidth(0) )
{
const int newValue = horizontalScrollBar()->value() + visualRect(current).topLeft().x() - m_FrozenTableViewLeft->columnWidth(0);
horizontalScrollBar()->setValue(newValue);
}
return current;
}
//! [navigate]
void FreezeTableWidget::scrollTo (const QModelIndex & index, ScrollHint hint){
if (index.column() > 0)
QTableView::scrollTo(index, hint);
}
//! [geometry]
void FreezeTableWidget::updateFrozenTableGeometry()
{
int nTableFrameWidth = frameWidth();
int nVerHeaderWidth = verticalHeader()->width();
int nHorHeaderHeight = horizontalHeader()->height();
int nViewPortHeight = viewport()->height();
int nTableViewWidthLeft = 0;
for (int i = 0; i < m_nFreezeColumnLeft; ++i)
{
nTableViewWidthLeft += columnWidth(i);
}
m_FrozenTableViewLeft->setGeometry(
nTableFrameWidth + nVerHeaderWidth,
nTableFrameWidth,
nTableViewWidthLeft,
nViewPortHeight + nHorHeaderHeight);
int nTableViewWidthRight = 0;
int nTableColCnt = model()->columnCount();
for (int i = nTableColCnt - m_nFreezeColumnRight; i < nTableColCnt; ++i)
{
nTableViewWidthRight += columnWidth(i);
}
int nRightTableX = this->width() - nTableViewWidthRight/* - 200*/;
m_FrozenTableViewRight->setGeometry(
nRightTableX,
nTableFrameWidth,
nTableViewWidthRight,
nViewPortHeight + nHorHeaderHeight);
}
//! [geometry]
使用:
FreezeTableWidget* pFreezeSpcTable = new FreezeTableWidget(this);
pFreezeSpcTable ->SetColumnFreezeLeft(3);
pFreezeSpcTable ->SetColumnFreezeRight(4);
pFreezeSpcTable ->SetModel(m_pTableModel);
使用起来基本没什么问题,可能moveCursor(), scrollTo 存在潜在问题,但尚未发现。