QTableView 在同时显示多个单元格时滚动缓慢

QTableView slow scrolling when many cells are visible at once

本文关键字:单元格 滚动 缓慢 显示 QTableView      更新时间:2023-10-16

>背景:我正在使用Qt 5.5.1开发应用程序,并使用msvc2013进行编译。在这个应用程序中,我使用我自己的QTableView实现,以及自定义QStyledItemDelegate(需要自定义单元格编辑)和QAbstractTableModel。我打算将此视图用于处理我包装在上述模型中的大量数据。我允许用户使用一些数据编辑选项、自定义排序、"无效"行结束等。

问题:我的 QTableView 子类的滚动速度很慢 - 显示的表格越多(通过调整窗口大小)它就越慢,例如显示 ~250 个单元格(全屏)= 慢,~70 个单元格显示(小窗口)= 快。

到目前为止,我尝试过:

  • 首先是检查我的模型是否减慢了速度 - 我测量了读取 10k 个样本的时间(使用 QTime::elapsed()),它显示 0 或 1ms。然后我简单地更改了QTableView::d ata方法,以始终返回预定义的字符串并且不获取任何真实数据。

    QVariant DataSet_TableModel::data(const QModelIndex &index, int role) const { if (role == Qt::ItemDataRole::DisplayRole) { return QVariant("aRatherLongString"); //results in slow scrolling //return QVariant("a"); // this instead results in fast scrolling } else return QVariant(); } 如您所见,速度似乎受每个单元格的字符数的影响,而不是受数据源的基础连接的影响。

  • 在我的QStyledItemDelegate的自定义实现中,我尝试了与上述相同的"技巧" - 这次过度绑定显示文本方法:

    QString DataSet_TableModel_StyledItemDelegate::displayText(const QVariant &value, const QLocale &locale) const { return "a" //fast // return "aRatherLongString"; //slow // return QStyledItemDelegate::displayText(value, locale); //default }

  • 经过与朋友的思考,我们得出结论,也许我们可以禁用单元格的绘制/绘画/更新,直到完成整个滚动操作。它可能会导致一些闪烁,但值得一试。不幸的是,我们真的不知道如何证明这一点。我们有永远的QTableView方法:scrollContentBy(int dx,int dy)和verticalScrollbarAction(int action) - 我们已经正确捕获了滚动动作(任何一种方法都会拦截它),并试图以某种方式禁用像这样重新绘制:

    void DataSet_TableView::verticalScrollbarAction(int action) { this->setUpdatesEnabled(false); QTableView::verticalScrollbarAction(action); this->setUpdatesEnabled(true); }

。但它没有任何可见的效果。我们应该如何处理它?我们是否需要在直接放在单元格中的项目上使用 setUpdatesEnabled()?(不确定这些是什么 - 小部件?

以下是作为测试此问题的一部分而拍摄的屏幕截图:

预定义文本,无需调用底层数据结构 - 滚动缓慢,"全屏"

预定义文本,无需调用底层数据结构 - 快速滚动,窗口化

请求:您能否帮助我查明原因并尽可能提出解决方案?是我使用的类的限制吗?

首先,您还应该在release模式下运行应用程序以检查您的性能,根据我的经验,使用debug模式时性能会大大降低。

其次,您需要注意,每次调整大小、滚动、聚焦、右键单击等时都会调用模型data方法和委托方法。这些操作会触发为每个显示的单元格调用这些方法,因此您需要确保不会执行任何不必要的处理。

单元格内的项是调用自己的方法的委托(例如:paint)。

一些特定的优化将有助于这些方法的实现C++例如使用 switch 而不是 if 语句,请参阅此处和此处的说明。条件(三元)运算符的使用也可能加快速度,更多信息在这里,这里和一些关于昂贵的支票的信息在这里。

此外,QVariant 以不同的方式处理文本,如下例所示,您应该尝试两种方式并检查速度是否有任何差异。有些转换比其他转换更昂贵。

v = QVariant("hello");          // The variant now contains a QByteArray
v = QVariant(tr("hello"));      // The variant now contains a QString