Что ж, кажется, я нашел решение, поэтому я поделюсь им здесь для тех, у кого есть такая же проблема, и кто гуглит эту тему.
Прежде всего, я обнаружил, что на самом деле это ошибка в Qt, зарегистрированная еще в 2011 году и до сих пор открытая: https://bugreports.qt.io/browse/QTBUG-16592
Я добавил к нему свой голос (и вы тоже должны!). Затем решил попробовать использовать QTableView вместо QListView - и, на удивление, мне удалось заставить его работать, или так кажется.
В отличие от QListView, QTableView изменяет размеры строк только по явному запросу, вызывая resizeRowToContents(rowNum). Таким образом, хитрость заключается в том, чтобы вызывать его своевременно для строк, которые становятся видимыми в окне просмотра.
Вот что я сделал:
Наследовать от QTableView (назовем его MyTableView)
Замените QListView на MyTableView и инициализируйте его таким образом в конструкторе. Это назначает делегата пользовательского элемента, скрывает заголовки таблиц и применяется в режиме выбора строки:
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 и публичную функцию, вычисляющую реальную высоту строк, но только тех, которые в данный момент видны:
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().
Вызовите updateVisibleRowHeights() после назначения модели экземпляру MyTableView, чтобы исходное представление было правильным:
table.setModel(&myModel);
table.updateVisibleRowHeights();
На самом деле это нужно делать в каком-нибудь методе MyTableView, который реагирует на изменения модели, но я оставлю это в качестве упражнения.
- Теперь все, что осталось, это заставить что-то вызывать updateRowHeights всякий раз, когда изменяется позиция вертикальной прокрутки таблицы. Итак, нам нужно добавить следующее в конструктор MyTableView:
connect(verticalScrollBar(), &QScrollBar::valueChanged, [this](int) {
updateRowHeights();
});
Готово - работает очень быстро даже с моделью из 100 000 элементов! И запуск мгновенный!
Базовый пример проверки концепции этой техники (с использованием чистого QTableView вместо подкласса) можно найти здесь: https://github.com/ajenter/qt_hugelistview/blob/tableview-experiment/src/main.cpp
Предупреждение: этот метод еще не проверен в бою и может содержать некоторые неизвестные проблемы. Используйте на свой страх и риск!
person
Alex Jenter
schedule
23.11.2020
QAbstractItemView::ScrollPerItem
и заранее указываете количество предметов (даже сcanFetchMore()
)? Что касается прыгающей полосы прокрутки... Однажды я сделал демонстрацию, чтобы сохранить текущий элемент в стабильном положении просмотра - независимо от того, вставлены ли элементы до или после него: Остановить прокрутку QTableView при добавлении данных над текущей позицией (хотя это зависит от использованияScrollPerPixel
.) :-( - person Scheff's Cat   schedule 20.11.2020QTreeView
иQTableView
. (СQListView
у меня на самом деле очень мало опыта.) Макетирование (т.е. определение размера для большого количества элементов) — это то, что я считаю одной из основных проблем. Я бы подумал, что это невозможно сделать лучше, но на самом деле я когда-то видел это лучше в gtkmm, с которого мы перешли на Qt, когда поддержка Windows стала ненадежной для gtkmm 3. Извините, что я не могу дать ничего похожего на ответ, но я Хотел бы поделиться с вами своими мыслями и чувствами. ;-) - person Scheff's Cat   schedule 20.11.2020