QAbstractItemView: don't calc update rect when there are to many indexes

With 8de62d34321cd827e60b0a7b6e7434070de301ae we try to avoid a complete
repaint by checking if the changed indexes are inside the visible rect.
This works fine when the amount of indexes to check is small but fails
otherwise. Therefore add a configurable, upper bound for this check.

Fixes: QTBUG-124173
Change-Id: I1aedd2cbe6e2d0090a640c8a1cf1cdb69f5b002a
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
This commit is contained in:
Christian Ehrlicher 2024-04-12 20:17:08 +02:00
parent c234700c83
commit ff33981992
4 changed files with 49 additions and 1 deletions

View File

@ -85,7 +85,8 @@ QAbstractItemViewPrivate::QAbstractItemViewPrivate()
delayedPendingLayout(true), delayedPendingLayout(true),
moveCursorUpdatedView(false), moveCursorUpdatedView(false),
verticalScrollModeSet(false), verticalScrollModeSet(false),
horizontalScrollModeSet(false) horizontalScrollModeSet(false),
updateThreshold(200)
{ {
keyboardInputTime.invalidate(); keyboardInputTime.invalidate();
} }
@ -3203,6 +3204,37 @@ int QAbstractItemView::sizeHintForColumn(int column) const
return width; return width;
} }
/*!
\property QAbstractItemView::updateThreshold
\since 6.9
This property holds the amount of changed indexes to directly trigger
a full update of the view inside dataChanged().
The algorithm inside dataChanged() tries to minimize a full update of the
view by calculating if the changed indexes are visible or not. For very
large models, with a lot of large changes, this might take longer than the
actual update so it's counter-productive. This property gives the ability
to control the algorithm to skip the check and directly trigger a full
update when the amount of changed indexes exceeds the given value.
The default value is 200.
\sa dataChanged()
*/
uint32_t QAbstractItemView::updateThreshold() const
{
Q_D(const QAbstractItemView);
return d->updateThreshold;
}
void QAbstractItemView::setUpdateThreshold(uint32_t threshold)
{
Q_D(QAbstractItemView);
if (d->updateThreshold == threshold)
return;
d->updateThreshold = threshold;
}
/*! /*!
Opens a persistent editor on the item at the given \a index. Opens a persistent editor on the item at the given \a index.
If no editor exists, the delegate will create a new editor. If no editor exists, the delegate will create a new editor.
@ -3397,6 +3429,11 @@ void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelInde
topLeft.row() > bottomRight.row() || topLeft.row() > bottomRight.row() ||
topLeft.column() > bottomRight.column()) { topLeft.column() > bottomRight.column()) {
// invalid parameter - call update() to redraw all // invalid parameter - call update() to redraw all
Q_ASSERT(false);
d->viewport->update();
} else if ((bottomRight.row() - topLeft.row() + 1ULL) *
(bottomRight.column() - topLeft.column() + 1ULL) > d->updateThreshold) {
// too many indices to check - force full update
d->viewport->update(); d->viewport->update();
} else { } else {
const QRect updateRect = d->intersectedRect(d->viewport->rect(), topLeft, bottomRight); const QRect updateRect = d->intersectedRect(d->viewport->rect(), topLeft, bottomRight);

View File

@ -46,6 +46,8 @@ class Q_WIDGETS_EXPORT QAbstractItemView : public QAbstractScrollArea
RESET resetVerticalScrollMode) RESET resetVerticalScrollMode)
Q_PROPERTY(ScrollMode horizontalScrollMode READ horizontalScrollMode Q_PROPERTY(ScrollMode horizontalScrollMode READ horizontalScrollMode
WRITE setHorizontalScrollMode RESET resetHorizontalScrollMode) WRITE setHorizontalScrollMode RESET resetHorizontalScrollMode)
Q_PROPERTY(uint32_t updateThreshold READ updateThreshold
WRITE setUpdateThreshold)
public: public:
enum SelectionMode { enum SelectionMode {
@ -177,6 +179,9 @@ public:
virtual int sizeHintForRow(int row) const; virtual int sizeHintForRow(int row) const;
virtual int sizeHintForColumn(int column) const; virtual int sizeHintForColumn(int column) const;
uint32_t updateThreshold() const;
void setUpdateThreshold(uint32_t threshold);
void openPersistentEditor(const QModelIndex &index); void openPersistentEditor(const QModelIndex &index);
void closePersistentEditor(const QModelIndex &index); void closePersistentEditor(const QModelIndex &index);
bool isPersistentEditorOpen(const QModelIndex &index) const; bool isPersistentEditorOpen(const QModelIndex &index) const;

View File

@ -421,6 +421,8 @@ public:
bool verticalScrollModeSet; bool verticalScrollModeSet;
bool horizontalScrollModeSet; bool horizontalScrollModeSet;
uint32_t updateThreshold;
virtual QRect visualRect(const QModelIndex &index) const { return q_func()->visualRect(index); } virtual QRect visualRect(const QModelIndex &index) const { return q_func()->visualRect(index); }
std::array<QMetaObject::Connection, 14> modelConnections; std::array<QMetaObject::Connection, 14> modelConnections;

View File

@ -295,6 +295,10 @@ void tst_QAbstractItemView::getSetCheck()
QCOMPARE(20, obj1->autoScrollMargin()); QCOMPARE(20, obj1->autoScrollMargin());
obj1->setAutoScrollMargin(16); obj1->setAutoScrollMargin(16);
QCOMPARE(16, obj1->autoScrollMargin()); QCOMPARE(16, obj1->autoScrollMargin());
QCOMPARE(200U, obj1->updateThreshold());
obj1->setUpdateThreshold(4711);
QCOMPARE(4711U, obj1->updateThreshold());
} }
void tst_QAbstractItemView::cleanup() void tst_QAbstractItemView::cleanup()