QAbstractTableModel::data方法调用次数过多

QAbstractTableModel::data method is called too many times

本文关键字:调用 data 方法 QAbstractTableModel      更新时间:2023-10-16

我需要一个表GUI控件,能够快速添加和显示大约10万项。出于这个原因,需要"虚拟"表控件,它只加载和显示可见的项。我尝试了QTableView和QAbstractTableModel:

class MyModel : public QAbstractTableModel
{
public:
MyModel(QObject * parent, IDataSource* dataSource) 
    : QAbstractTableModel(parent), m_dataSource(dataSource) {}
int rowCount(const QModelIndex& parent = QModelIndex()) const
{
    return m_dataSource->rowCount();
}
int columnCount(const QModelIndex& parent = QModelIndex()) const
{
    return 3;
}
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const
{
    if (role == Qt::DisplayRole)
    {
            return m_dataSource->cell(index.row(), index.column());
    }
    return QVariant();
}
bool addItem()
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    endInsertRows();
    return true;
}
private:
IDataSource* m_dataSource;
};
...
MyModel* model = new MyModel(this, this);
m_ui.tableView->setModel(model);
m_ui.tableView->show();

问题是MyModel::data()在添加新项目到可见区域时被调用。这使得性能大大降低。下面是更具体的测试场景:

  1. 视图一次只能显示5个元素
  2. 我用MyModel::addItems添加了20个项目。
  3. MyModel::data被所有可见的项目调用。
  4. MyModel::data继续被调用为可见的项目(1…5),当项目6,7,9…

我想也许这可能是由于添加新项目时重新绘制的垂直滚动条引起的,并且似乎使所有QListView重新绘制。但是在隐藏垂直滚动条之后,这个问题仍然存在。请建议。

我不知道如何防止endInsertRows调用导致对data()方法的额外调用。但是对多个项目调用一次endInsertRows可以解决性能问题。所以我调用:

beginInsertRows(QModelIndex(), rowCount(), rowCount() + 1000);
endInsertRows();

而不是调用1000次:

beginInsertRows(QModelIndex(), rowCount(), rowCount());
endInsertRows();

您的dataSource->cell()实现的渐近复杂性是多少?data()确实可能被调用很多次,如果你在上面放一个QSortFilterProxyModel来排序,甚至会调用更多。为了确保具有大量数据的项视图的性能,data()必须只需要恒定的时间来实现。