C++ 如何防止QListView调用每个项目的sizeHint?
我有一个QListView,里面有很多不同高度的项目。我实现了一个用于绘制项目的自定义委托,并将布局模式设置为批处理 但是,当分配模型时,列表视图会预先为模型中的每个项目请求sizeHint,忽略批处理设置,从而破坏性能,因为要计算大小,代理必须布局大量文本(这不是很快) 也许它这样做是为了计算滚动条的位置,但我认为当项目数量很大时,滚动条的位置只能基于项目索引,而不考虑项目高度。然而,QListView似乎不是这样工作的 我还尝试在模型中使用canFetchMore/fetchMore,但这会导致糟糕的用户体验-滚动条位置不再准确,当加载更多项目时列表会跳转,这一点都不平滑 因此,问题是:C++ 如何防止QListView调用每个项目的sizeHint?,c++,qt,qlistview,qtwidgets,C++,Qt,Qlistview,Qtwidgets,我有一个QListView,里面有很多不同高度的项目。我实现了一个用于绘制项目的自定义委托,并将布局模式设置为批处理 但是,当分配模型时,列表视图会预先为模型中的每个项目请求sizeHint,忽略批处理设置,从而破坏性能,因为要计算大小,代理必须布局大量文本(这不是很快) 也许它这样做是为了计算滚动条的位置,但我认为当项目数量很大时,滚动条的位置只能基于项目索引,而不考虑项目高度。然而,QListView似乎不是这样工作的 我还尝试在模型中使用canFetchMore/fetchMore,但这会
请注意巨大的启动延迟和调试消息,显示所有5000项的sizeHint都是预先请求的。看来我已经找到了解决方案,所以我将在这里分享,以方便有相同问题的人使用谷歌搜索此线程 首先,我发现这实际上是Qt中的一个bug,该bug在2011年注册并仍然存在: 我已经投了我的一票(你也应该投!)。 然后决定尝试使用QTableView而不是QListView——令人惊讶的是,我成功地使它工作了,或者看起来是这样 与QListView不同,QTableView仅在显式请求时通过调用resizeRowToContents(rowNum)调整行的大小。因此,诀窍是对视口中可见的行以实时方式调用它 以下是我所做的:
警告:这项技术尚未经过战斗验证,可能包含一些未知问题。使用风险自负 如果您使用
qabstractemview::ScrollPerItem
并预先提供项目数(即使使用canFetchMore()
)?关于跳转滚动条。。。我曾经做过一个演示,让当前项目保持在稳定的视图位置,不管项目是在它之前还是之后插入的:(不过,这取决于使用ScrollPerPixel
):-(@Scheff:无论垂直滚动模式如何,行为都是相似的-所有项目的大小提示都是预先请求的,这对我来说根本没有意义,因为我已经明确地将批量大小设置为只有10个项目。我使用的是Qt 6中的错误吗?关于canFetchMore,感谢链接!据我所知,它需要QTableView-您是否建议切换到QTableView而不是QListView?我在QTreeView
和QTableView
中一直在努力解决性能问题。(使用QListView
,我实际上没有多少经验。)布局(即确定大量项目的大小)这也是我认为最重要的问题之一。我认为这是再好不过的了,但事实上,我曾经在gtkmm中看到过更好的情况,当Windows对gtkmm 3的支持变得不可靠时,我们从gtkmm切换到Qt。很抱歉,我无法提供任何类似的答案,但我想与您分享我的感受。;-)我明白了,谢谢你分享你的经验!
MyTableView::MyTableView(QWidget* parent) : QTableView(parent)
{
setSelectionBehavior(QAbstractItemView::SelectRows);
horizontalHeader()->setStretchLastSection(true);
horizontalHeader()->hide();
verticalHeader()->hide();
setItemDelegateForColumn(0, new CustomDelegate(&table)); // for custom-drawn items
}
QItemSelection _itemsWithKnownHeight; // private member of MyTableView
void MyTableView::updateVisibleRowHeights()
{
const QRect viewportRect = table.viewport()->rect();
QModelIndex topRowIndex = table.indexAt(QPoint(viewportRect.x() + 5, viewportRect.y() + 5));
QModelIndex bottomRowIndex = table.indexAt(QPoint(viewportRect.x() + 5, viewportRect.y() + viewportRect.height() - 5));
qDebug() << "top row: " << topRowIndex.row() << ", bottom row: " << bottomRowIndex.row();
for (auto i = topRowIndex.row() ; i < bottomRowIndex.row() + 1; ++i)
{
auto index = model()->index(i, 0);
if (!_itemsWithKnownHeights.contains(index))
{
resizeRowToContents(i);
_itemsWithKnownHeights.select(index, index);
qDebug() << "Marked row #" << i << " as resized";
}
}
}
table.setModel(&myModel);
table.updateVisibleRowHeights();
connect(verticalScrollBar(), &QScrollBar::valueChanged, [this](int) {
updateRowHeights();
});