QTableView冻结左右部分列,中间列滚动实现

主要参考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 存在潜在问题,但尚未发现。

相关推荐

  1. Excel——冻结前三

    2024-06-17 23:26:03       59 阅读
  2. 实现

    2024-06-17 23:26:03       39 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-17 23:26:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-17 23:26:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-06-17 23:26:03       87 阅读
  4. Python语言-面向对象

    2024-06-17 23:26:03       96 阅读

热门阅读

  1. Linux安装docker

    2024-06-17 23:26:03       28 阅读
  2. xss-lab靶场的level15-level20

    2024-06-17 23:26:03       25 阅读
  3. 知识库的创建(1) - KnowledgeFile文件加载和分割

    2024-06-17 23:26:03       26 阅读
  4. Flink集群架构

    2024-06-17 23:26:03       20 阅读
  5. PCA 在图像分析上的应用

    2024-06-17 23:26:03       28 阅读
  6. 第二章 - 第1节- 逻辑运算 -课后习题

    2024-06-17 23:26:03       32 阅读
  7. 用最简单的方式理解函数重载

    2024-06-17 23:26:03       31 阅读
  8. 【Python高级编程】OpenCV来处理视频数据

    2024-06-17 23:26:03       25 阅读
  9. LeetCode //C - 171. Excel Sheet Column Number

    2024-06-17 23:26:03       26 阅读
  10. kotlin `FloatArray` 和 `Array<Float>`

    2024-06-17 23:26:03       24 阅读
  11. CSS 列表样式(ul)全面解析

    2024-06-17 23:26:03       31 阅读