当许多单元格同时可见时,QTableView 滚动缓慢

Posted

技术标签:

【中文标题】当许多单元格同时可见时,QTableView 滚动缓慢【英文标题】:QTableView slow scrolling when many cells are visible at once 【发布时间】:2016-04-24 20:27:17 【问题描述】:

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

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

到目前为止我做了什么尝试:

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

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 自定义实现中,我尝试了与上面相同的“技巧” - 这次覆盖 displayText 方法:

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 方法:scrollContentsBy(int dx, int dy) 和 verticalScrollbarAction(int action) - 我们已经正确捕获了滚动动作(任何一种方法都会拦截它)并试图以某种方式禁用重新绘制,如下所示:

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

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

以下是测试此问题时截取的屏幕截图:

Predefined text, no calls to underlying data structure - slow scrolling, 'full screen'

Predefined text, no calls to underlying data structure - fast scrolling, windowed

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

【问题讨论】:

您是否尝试过使用分析工具对其进行分析? 不,我没有。我可能会尝试使用分析器,但我还没有学会如何使用它(并找到合适的工具)——这需要一些时间。 您的项目是否都相同大小 - 如果是,您是否设置了视图的 uniformItemSizes 属性。这会对性能产生相当大的影响。 @TobySpeight 我确实尝试过这样做,但是QTableView没有任何类似于uniformItemSizes的属性(看起来你在谈论QListView)。我尝试在视图构造函数的两个标题上使用 setDefaultSectionSize(mySize)、setSectionResizeMode(QHeaderView::Fixed) 和 resizeSections(QHeaderView::Fixed) - 滚动速度没有积极变化。 @FrankOsterfeld 我和朋友做了一些分析,得到的结果是这样的:[link]i.imgsafe.org/9a0d81a.png(使用 luke stackwalker) - 不幸的是,我们目前缺乏从这个结果中做出任何事情的知识。测试仅包含滚动动作。一项测试是用空的 QVariant 完成的,而且速度很快,另一项测试是在 QVariant 中使用 QString - 这个测试很慢。 【参考方案1】:

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

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

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

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

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

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

【讨论】:

以上是关于当许多单元格同时可见时,QTableView 滚动缓慢的主要内容,如果未能解决你的问题,请参考以下文章

向下滚动时,UITableview 看不到最后一个单元格

如何滚动到第一个单元格,同时在 CollectionView 上滑动最后一个单元格?

UITableView 滚动时动画单元格

UICollectionViewCell 滚动时缩放单元格大小

使用平移手势选择多个表格视图单元格

当单元格不可见时,UITableView indexPathForCell 返回 null