QTableWidget是使用QStandardItemModel作为数据模型的,如果要实现大量数据的加载并支持排序,可以考虑继承QAbstractItemModel,自定义一个数据模型来替代QStandardItemModel。下面是一个示例代码:
#include <QApplication>
#include <QTableWidget>
#include <QHeaderView>
#include <QScrollBar>
#include <QTimer>
#include <QAbstractItemModel>
const int ROWS_PER_PAGE = 100; // 每页显示的行数
const int TOTAL_ROWS = 10000; // 数据总行数
class MyTableModel : public QAbstractItemModel
{
Q_OBJECT
public:
MyTableModel(QObject *parent = nullptr)
: QAbstractItemModel(parent)
, m_rows(TOTAL_ROWS)
{
for (int i = 0; i < m_rows.size(); ++i) {
QVector<QVariant> row;
row.append(QString("Item %1").arg(i));
row.append(qrand() % 100);
m_rows[i] = row;
}
}
QVariant data(const QModelIndex &index, int role) const override
{
if (!index.isValid())
return QVariant();
if (role == Qt::DisplayRole) {
return m_rows[index.row()][index.column()];
}
return QVariant();
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
if (parent.isValid())
return 0;
return m_rows.size();
}
int columnCount(const QModelIndex &parent = QModelIndex()) const override
{
if (parent.isValid())
return 0;
return 2;
}
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
{
if (parent.isValid() || row < 0 || row >= m_rows.size() || column < 0 || column >= 2)
return QModelIndex();
return createIndex(row, column);
}
QModelIndex parent(const QModelIndex &index) const override
{
Q_UNUSED(index);
return QModelIndex();
}
Qt::ItemFlags flags(const QModelIndex &index) const override
{
if (!index.isValid())
return Qt::NoItemFlags;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal) {
switch (section) {
case 0:
return QString("Name");
case 1:
return QString("Value");
default:
return QVariant();
}
}
return QVariant();
}
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override
{
if (column < 0 || column >= 2)
return;
if (order == Qt::AscendingOrder)
std::sort(m_rows.begin(), m_rows.end(), [&](const QVector<QVariant>& row1, const QVector<QVariant>& row2) {
return row1[column] < row2[column];
});
else
std::sort(m_rows.begin(), m_rows.end(), [&](const QVector<QVariant>& row1, const QVector<QVariant>& row2) {
return row1[column] > row2[column];
});
emit layoutChanged();
}
private:
QVector<QVector<QVariant>> m_rows;
};
class TableWidget : public QTableWidget
{
Q_OBJECT
public:
TableWidget(QWidget *parent = nullptr)
: QTableWidget(parent)
, m_rowCount(0)
, m_currentPage(0)
{
setSortingEnabled(true); // 开启排序功能
horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); // 自适应列宽
verticalScrollBar()->setSingleStep(ROWS_PER_PAGE); // 设置滚动条步长
m_model = new MyTableModel(this);
setModel(m_model);
connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(onScrollBarValueChanged(int)));
QTimer::singleShot(0, this, SLOT(loadData())); // 延时加载数据
}
private slots:
void onScrollBarValueChanged(int value)
{
if (value == verticalScrollBar()->maximum()) {
// 如果滚动到底部了,尝试加载下一页数据
if ((m_currentPage + 1) * ROWS_PER_PAGE < TOTAL_ROWS) {
++m_currentPage;
loadData();
}
}
}
void loadData()
{
int rowsToAdd = qMin(TOTAL_ROWS - m_rowCount, ROWS_PER_PAGE);
for (int i = m_rowCount; i < m_rowCount + rowsToAdd; ++i) {
QVector<QVariant> row;
row.append(QString("Item %1").arg(i));
row.append(qrand() % 100);
m_model->beginInsertRows(QModelIndex(), i, i);
m_model->m_rows.append(row);
m_model->endInsertRows();
}
m_rowCount += rowsToAdd;
}
private:
int m_rowCount; // 已加载的行数
int m_currentPage; // 当前页数
MyTableModel *m_model;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TableWidget w;
w.show();
return a.exec();
}
#include "main.moc"
在这个示例代码中,我们自定义了一个MyTableModel类,继承自QAbstractItemModel,并且实现了data、rowCount、columnCount、index、parent、flags、headerData和sort等函数。其中,sort函数是用来支持排序功能的,利用std::sort对数据进行排序并发射layoutChanged信号来更新表格。
因为MyTableModel是一个自定义的数据模型,所以在TableWidget中需要通过setModel函数来设置表格的数据模型,并且在loadData函数中使用beginInsertRows和endInsertRows函数来动态地更新模型中的数据。