QTableWidget无限加载

#pragma once

#include <QTableWidget>
#include <functional>

class SimpleTable : public QTableWidget
{
	Q_OBJECT
public:
	typedef std::function<QWidget*(void* data)> CreateColWidgetFunc;
	typedef std::function<void(void* data)> DeleteDataFunc;

	explicit SimpleTable(QWidget *parent = 0);
	virtual ~SimpleTable();

	void init(int rowHeight, const std::vector<CreateColWidgetFunc> &createFuncs, const DeleteDataFunc &delFunc);
	void initData(const std::map<quint64, void*> &data, const std::function<bool(quint64, quint64)> &sortCond = nullptr);

	const std::map<quint64, void*>& constDatas() const;
	std::map<quint64, void*>& datas();
	const std::vector<quint64>& constIds() const;
	std::vector<quint64>& ids();
	std::vector<quint64> srcIds();

	void* findData(int row);
	void resetContent();
	void refreshVisible();
	std::vector<quint64> getSelectedIds() const;
	void setSelectedIds(const std::vector<quint64> &ids);

	void deleteDataWidget(std::vector<int> rows);
	void addDataWidget(quint64 id, void* data);
	void modifyDataWidget(int row);
	void sort(const std::function<bool(quint64, quint64)> &compFunc);

private:
	void clearData();
	void deleteWidget(int row);
	void setRowWidget(int row);
	void setSelectedRows(const std::vector<int> &rows);

private:
	std::vector<CreateColWidgetFunc> m_createColWidgetFuncs;
	DeleteDataFunc m_deleteDataFunc;
	std::vector<quint64> m_ids;
	std::map<quint64, void*> m_datas;
	bool m_isFilter;
	int m_visibleCount;
	int m_rowHeight;
};



#include "simpletable.h"
#include <QtWidgets>
#include <set>

#include <QDebug>
#include <QTime>

static const int s_itemFlag = 0xfff;
SimpleTable::SimpleTable(QWidget *parent)
	: QTableWidget(parent), m_visibleCount(0), m_rowHeight(0), m_isFilter(false)
{
	//this->horizontalHeader()->hide();
	//this->verticalHeader()->hide();
	//this->setSelectionBehavior(QAbstractItemView::SelectRows);  // 选择行
	//this->setSelectionMode(QAbstractItemView::ExtendedSelection); // 选中多个目标
	//this->setEditTriggers(QAbstractItemView::NoEditTriggers);   // 不能编辑
	//this->verticalHeader()->setVisible(false);
	//this->setFrameShape(QFrame::NoFrame);
	//this->setShowGrid(false);

	this->setAutoScroll(false);
	connect(this->verticalScrollBar(), &QScrollBar::valueChanged, [this] (int value) {
		static int oldValue = 0;

		if (value > oldValue) {
			if (this->rowCount() - value < m_visibleCount) {
				value = this->rowCount() - m_visibleCount;
			}
			for (int i=oldValue; i<value; i++) {
				deleteWidget(i);
			}
		} else {
			int end = qMin(oldValue + m_visibleCount, this->rowCount());
			for (int i=value + m_visibleCount; i<end; i++) {
				deleteWidget(i);
			}
		}

		int start = qMax(0, value);
		int end = qMin(m_visibleCount + value, this->rowCount());
		for (int i = start; i < end; i++) {
			QTableWidgetItem *item = this->item(i, 0);
			if (!item) {
				continue;
			}
			int flag = item->data(Qt::UserRole + s_itemFlag).toInt();
			int colCount = m_createColWidgetFuncs.size();
			if (0 == flag && colCount > 0) {
				this->setRowWidget(i);
			}
		}

		oldValue = start;
	});

	connect(this->verticalScrollBar(), &QScrollBar::rangeChanged, [this] (int min, int max) {
		if (m_rowHeight > 0) {
			int newVisualCount = this->height() / m_rowHeight + 1;
			if (m_visibleCount != newVisualCount) {
				m_visibleCount = newVisualCount;
				emit this->verticalScrollBar()->valueChanged(this->verticalScrollBar()->value());
			} else {
				int start = this->verticalScrollBar()->value();
				int end = qMin<int>(this->rowCount(), start + m_visibleCount);
				for (int i=start; i<end; i++) {
					QTableWidgetItem *item = this->item(i, 0);
					if (!item) {
						continue;
					}

					if (0 == item->data(Qt::UserRole + s_itemFlag).toInt()) {
						this->setRowWidget(i);
					}
				}
			}
		}
	});
}

SimpleTable::~SimpleTable()
{
	clearData();
}

void SimpleTable::init(int rowHeight, const std::vector<CreateColWidgetFunc> &createFuncs, const DeleteDataFunc &delFunc)
{
this->setColumnCount(createFuncs.size());
 m_rowHeight = rowHeight;
	m_createColWidgetFuncs = createFuncs;
	m_deleteDataFunc = delFunc;
}

void SimpleTable::initData(const std::map<quint64, void*> &data, const std::function<bool(quint64, quint64)> &sortCond)
{
	clearData();
	m_datas = data;
	auto iter = data.begin();
	for ( ; iter != data.end(); ++iter) {
		m_ids.push_back(iter->first);
	}

	if (sortCond) {
		std::sort(m_ids.begin(), m_ids.end(), sortCond);
	}

	resetContent();
}

const std::map<quint64, void*>& SimpleTable::constDatas() const
{
	return m_datas;
}

std::map<quint64, void*>& SimpleTable::datas()
{
	return m_datas;
}

const std::vector<quint64>& SimpleTable::constIds() const
{
	return m_ids;
}

std::vector<quint64>& SimpleTable::ids()
{
	return m_ids;
}

std::vector<quint64> SimpleTable::srcIds()
{
	std::vector<quint64> result;
	auto iter = m_datas.begin();
	for ( ; iter != m_datas.end(); ++iter) {
		result.push_back(iter->first);
	}
	return result;
}

void* SimpleTable::findData(int row)
{
	if (row >=0 && row < (int)m_ids.size()) {
		return m_datas.at(m_ids.at(row));
	}
	return NULL;
}

void SimpleTable::resetContent()
{
	this->verticalScrollBar()->setValue(0);
	this->clearContents();

	int rowCount = m_ids.size();
	this->setRowCount(rowCount);
	if (m_rowHeight > 0) {
		m_visibleCount = this->height() / m_rowHeight + 1;
	}

	int colCount = this->columnCount();
	auto citer = m_ids.cbegin();
	for (int row=0; citer != m_ids.cend(); ++row, ++citer) {
		this->setRowHeight(row, m_rowHeight);
		for (int col=0; col<colCount; ++col) {
			QTableWidgetItem *item = new QTableWidgetItem();
			this->setItem(row, col, item);
			if (0 == col) {
				if (row < m_visibleCount) {
					this->setRowWidget(row);
					item->setData(Qt::UserRole + s_itemFlag, 1);
				} else {
					item->setData(Qt::UserRole + s_itemFlag, 0);
				}
			}
		}
	}
}

void SimpleTable::refreshVisible()
{
	int start = this->verticalScrollBar()->value();
	int end = qMin(start + m_visibleCount, this->rowCount());
	for (int i=start; i<end; i++) {
		setRowWidget(i);
	}
}

std::vector<quint64> SimpleTable::getSelectedIds() const
{
	QList<QTableWidgetItem*> selectedItems = this->selectedItems();
	std::vector<quint64> selectedIds;
	foreach (QTableWidgetItem *item, selectedItems) {
		quint64 id = m_ids[item->row()];
		if (selectedIds.end() == std::find(selectedIds.begin(), selectedIds.end(), id)) {
			selectedIds.push_back(id);
		}
	}

	return selectedIds;
}

void SimpleTable::setSelectedIds(const std::vector<quint64> &ids)
{
	std::vector<int> newSelectedRows;
	auto beginIter = m_ids.begin();
	auto iter = ids.begin();
	for ( ; iter != ids.end(); ++iter) {
		auto findIter = std::find(m_ids.begin(), m_ids.end(), *iter);
		if (findIter != m_ids.end()) {
			newSelectedRows.push_back(findIter - beginIter);
		}
	}
	this->setSelectedRows(newSelectedRows);
}

void SimpleTable::deleteDataWidget(std::vector<int> rows)
{
	std::sort(rows.begin(), rows.end(), [](int left, int right) { return left > right; });
	auto iter = rows.begin();
	for ( ; iter != rows.end(); ++iter) {
		int row = *iter;
		if (row >= 0 && row < (int)m_ids.size()) {
			this->removeRow(row);
			m_deleteDataFunc(m_datas.at(m_ids.at(row)));
			m_datas.erase(m_ids.at(row));
			m_ids.erase(m_ids.begin() + row);
		}
	}
}

void SimpleTable::addDataWidget(quint64 id, void* data)
{
	if (!data) {
		return;
	}

	if (m_datas.find(id) != m_datas.end()) {
		return;
	}

	m_ids.push_back(id);
	m_datas[id] = data;
	int colCount = this->columnCount();
	int newRow = this->rowCount();
	this->insertRow(newRow);
	this->setRowHeight(newRow, m_rowHeight);
	for (int col=0; col<colCount; ++col) {
		QTableWidgetItem *item = new QTableWidgetItem();
		this->setItem(newRow, col, item);
		if (0 == col) {
			if (newRow < m_visibleCount) {
				this->setRowWidget(newRow);
				item->setData(Qt::UserRole + s_itemFlag, 1);
			} else {
				item->setData(Qt::UserRole + s_itemFlag, 0);
			}
		}
	}
}

void SimpleTable::modifyDataWidget(int row)
{
	setRowWidget(row);
}

void SimpleTable::sort(const std::function<bool(quint64, quint64)> &compFunc)
{
	if ((int)m_ids.size() < this->rowCount()) {
		return;
	}

	std::vector<quint64> oldSelectedIds = this->getSelectedIds();
	std::sort(m_ids.begin(), m_ids.end(), compFunc);
	refreshVisible();
	if (oldSelectedIds.size() > 0) {
		this->setSelectedIds(oldSelectedIds);
	}
}

void SimpleTable::clearData()
{
	m_ids.clear();
	auto iter = m_datas.begin();
	if (m_deleteDataFunc) {
		auto iter = m_datas.begin();
		for ( ; iter != m_datas.end(); ++iter) {
			m_deleteDataFunc(iter->second);
		}
	}
	m_datas.clear();
}

void SimpleTable::deleteWidget(int row)
{
	if (row < 0 || row >= this->rowCount()) {
		return;
	}

	QTableWidgetItem *item = this->item(row, 0);
	if (item->data(Qt::UserRole + s_itemFlag).toInt() == 1) {
		int colCount = this->columnCount();
		for (int col=0; col<colCount; ++col) {
			this->removeCellWidget(row, col);
		}
		item->setData(Qt::UserRole + s_itemFlag, 0);
	}
}

void SimpleTable::setRowWidget(int row)
{
	if (row < 0 || row >= this->rowCount() || row >= (int)m_ids.size()) {
		return;
	}

	QTableWidgetItem *item = this->item(row, 0);
	if (item->data(Qt::UserRole + s_itemFlag).toInt() == 1) {
		deleteWidget(row);
	}

	item->setData(Qt::UserRole + s_itemFlag, 1);
	int colCount = qMin<int>(m_createColWidgetFuncs.size(), this->columnCount());
	for (int col=0; col<colCount; ++col) {
		void* data = m_datas.at(m_ids.at(row));
		if (data) {
			this->setCellWidget(row, col, m_createColWidgetFuncs[col](data));
		}
	}
}

void SimpleTable::setSelectedRows(const std::vector<int> &rows)
{
	QItemSelectionModel *selectionModel = this->selectionModel();
	QItemSelection itemSelection = selectionModel->selection();
	selectionModel->clearSelection();
	itemSelection.clear();

	auto iter = rows.begin();
	for ( ; iter != rows.end(); ++iter) {
		this->selectRow(*iter);
		itemSelection.merge(selectionModel->selection(), QItemSelectionModel::Select);
	}

	selectionModel->select(itemSelection, QItemSelectionModel::Select);
}



用法:

std::vector<SimpleTable::CreateColWidgetFunc> createColWidgetFuncs;
createColWidgetFuncs.push_back([](void* data) -> QWidget* { return new ColWidget::FirstWidget(data); });
createColWidgetFuncs.push_back([](void* data) -> QWidget* { return new ColWidget::SecondWidget(data); });
createColWidgetFuncs.push_back([](void* data) -> QWidget* { return new ColWidget::ThirdWidget(data); });
ui->tableWidget->init(ROW_WIDGET_HEIGHT, createColWidgetFuncs, [](void* data) { if (data) delete (ColWidget::Data*)data; });

		ui->tableWidget->initData(initData, [this](quint64 left, quint64 right) -> bool {
			const std::map<quint64, void*> &srcData = ui->tableWidget->constDatas();
			Data *leftData = static_cast<Data*>(srcData.at(left));
			Data *rightData = static_cast<Data*>(srcData.at(right));
			if (leftData->sortAuth == rightData->sortAuth) {
				return leftData->name < rightData->name;
			} else {
				return leftData->sortAuth > rightData->sortAuth;
			}
		});


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值