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);
	QHeaderView * GetLeftTableHorizontalHeader();
	
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();
}

QHeaderView * FreezeTableWidget::GetLeftTableHorizontalHeader()
{
	return m_FrozenTableViewLeft->horizontalHeader();
}

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* pFreezeTable = new FreezeTableWidget(this);
pFreezeTable ->SetColumnFreezeLeft(3);
pFreezeTable  ->SetColumnFreezeRight(4);
pFreezeTable ->SetModel(m_pTableModel);
使用起来基本没什么问题,可能moveCursor(), scrollTo 存在潜在问题,但尚未发现。

排序
注意:如果要对表格内容进行排序,由于是三个QTableView,因此需要分别连接对应的TableView的horizontalHeader的sectionClicked信号(下面代码只连接了两个,左侧冻结表和主表)。

// 排序
QHeaderView *headerView = pFreezeTable ->horizontalHeader();
connect(headerView, SIGNAL(sectionClicked(int)), this, SLOT(sort_header_slot(int)));
QHeaderView *headerViewLeft = pFreezeTable ->GetLeftTableHorizontalHeader();
connect(headerViewLeft, SIGNAL(sectionClicked(int)), this, SLOT(sort_header_slot(int)));

槽函数根据数据及业务需求实现即可。

bool g_asc = true;
void MainWindow::sort_header_slot(int id)
{
	QList<QList<QString>> datas = m_pTableModel->GetData(); // m_pTableModel是继承于QTableModel的派生类对象
	if (g_asc)
		sort(datas.begin(), datas.end(), [&](QList<QString> info1, QList<QString> info2) {
		return abs(info1[id].toDouble()) < abs(info2[id].toDouble());
			});
	else
		sort(datas.begin(), datas.end(), [&](QList<QString> info1, QList<QString> info2) {
		return abs(info1[id].toDouble()) > abs(info2[id].toDouble());
			});
	g_asc = !g_asc;
	m_pTableModel->setData(datas);

	ResetTableModel(); // 其它设置
}

void MainWindow::ResetSPCTableModel()
{
	QItemSelectionModel *selectionModel = pFreezeTable->selectionModel();
	pFreezeTable->setModel(nullptr);
	if (selectionModel)
		delete selectionModel;

	pFreezeTable ->SetModel(m_pTableModel);
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值