gpt4 book ai didi

c++ - 如何防止 QListView 调用每个项目的 sizeHint?

转载 作者:行者123 更新时间:2023-12-03 07:14:55 26 4
gpt4 key购买 nike

我有一个 QListView 有很多不同高度的项目。我实现了一个自定义委托(delegate)来绘制项目并将布局模式设置为批处理。
但是,当分配模型时, ListView 会预先为模型中的每个项目请求 sizeHint,忽略 Batched 设置并因此破坏性能,因为要计算大小,委托(delegate)必须布局大量文本(这并不快)。
可能它这样做是为了计算滚动条位置,但我认为当项目数量很大时,滚动条位置可以仅基于项目索引,而不考虑项目高度。然而,这似乎不是 QListView 的工作方式。
我也尝试在模型中使用canFetchMore/fetchMore,但这会导致糟糕的用户体验——滚动条位置不再准确,加载更多项目时列表会跳来跳去,一点都不流畅。
所以,问题是:

  • 有没有办法防止 QListView 为不可见的项目调用 sizeHint?
  • 如果唯一的方法是使用canFetchMore/fetchMore,如何获得平滑滚动和稳定准确的滚动条?

  • 非常感谢!
    更新:这是重现此行为的最小示例:
    https://github.com/ajenter/qt_hugelistview
    请注意巨大的启动延迟和显示所有 5000 个项目的 sizeHint 是预先请求的调试消息。

    最佳答案

    好吧,看来我已经找到了解决方案,所以我会在这里分享它,以供有同样问题并在谷歌上搜索该线程的任何人。
    首先,我发现这实际上是 2011 年注册的 Qt 中的一个错误,并且仍然存在:
    https://bugreports.qt.io/browse/QTBUG-16592
    我已经投票了(你也应该投票!)。
    然后决定尝试使用 QTableView 而不是 QListView - 而且,令人惊讶的是,我设法让它工作,或者看起来如此。
    与 QListView 不同,QTableView 仅在显式请求时通过调用 resizeRowToContents(rowNum) 来调整行的大小。因此,诀窍是以即时方式为在视口(viewport)中可见的行调用它。
    这是我所做的:

  • 继承自QTableView(我们称之为MyTableView)
  • 将 QListView 替换为 MyTableView 并在构造函数中像这样初始化它。这会分配自定义项目委托(delegate),隐藏表格标题并应用“按行”选择模式:
  •    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
    }
  • 在 MyTableView 中,添加一个 QItemSelection 私有(private)字段和一个计算行实际高度的公共(public)函数,但仅计算当前可见的行:
  • 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";
    }
    }
    }
  • 注意:如果项目高度取决于控件的宽度,则需要覆盖 resizeEvent() , 清除 _itemsWithKnownHeights ,然后再次调用 updateVisibleRowsHeight()。
  • 将模型分配给 MyTableView 实例后调用 updateVisibleRowHeights() ,以便初始 View 正确:
  •    table.setModel(&myModel);
    table.updateVisibleRowHeights();
    事实上,它应该在一些 MyTableView 对模型更改使用react的方法中完成,但我将把它留作练习。
  • 现在剩下的就是在表格的垂直滚动位置发生变化时调用 updateRowHeights 。所以我们需要在 MyTableView 的构造函数中添加以下内容:
  • connect(verticalScrollBar(), &QScrollBar::valueChanged, [this](int) {
    updateRowHeights();
    });
    完成 - 即使有 100,000 个项目的模型,它也能运行得非常快!并且启动是瞬间的!
    可以在此处找到该技术的基本概念验证示例(使用纯 QTableView 而不是子类):
    https://github.com/ajenter/qt_hugelistview/blob/tableview-experiment/src/main.cpp
    警告:此技术尚未经过实战验证,可能包含一些未知问题。使用风险自负!

    关于c++ - 如何防止 QListView 调用每个项目的 sizeHint?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64924570/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com