当许多单元格同时可见时,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 滚动缓慢的主要内容,如果未能解决你的问题,请参考以下文章
如何滚动到第一个单元格,同时在 CollectionView 上滑动最后一个单元格?