QAbstractItemModel: much time lost on nothing between beginResetModel() and endResetModel()
-
MyTableModel
inherits fromQAbstractItemModel
.Occasionally, my data change deeply: new number of rows, and new contents in each single row. So I call from within
MyTableModel
:beginResetModel(); endResetModel();
This redraws the entire table, calling numerous times the function
MyTableModel::data
(which overridesQAbstractItemModel::data
). Works perfectly, but too slowly. For a table with a few thousand entries, it takes several seconds frombeginResetModel
toendResetModel
.Of course my first suspicion was that computations in my own
data
function take too long. So I replaced it byQVariant MyTableModel::data(const QModelIndex& index, int role) const override { return {}; }
Almost no effect. The seconds are really spent on some Qt internal overhead.
Questions, obviously: What is Qt doing? How to make it faster?
-
@Joachim-W
begin/endResetModel()
tell any attached views that the model has changed, and they need to redraw. They are the callers of thedata()
method.You need to look at whatever views you have attached to the model are up to for the time taken. I don't know how long it takes your view(s) to redraw against "a table with a few thousand entries".
-
@JonB
MyTableView
inherits fromQTreeView
(and not fromQTableView
, which for forgotten reasons did not yield the right layout). Upon signalQAbstractItemModel::modelReset
, it callsQTreeView::resizeColumnToContents
for each column. This is probably a stupid thing to do as it callsMyTableModel::data
for all columns and all rows. Yet I wonder: why does this overhead machinery by itself consume much more time than whatever computations withinMyTableModel::data
? -
@Joachim-W said in QAbstractItemModel: much time lost on nothing between beginResetModel() and endResetModel():
Yet I wonder: why does this overhead machinery by itself consume much more time than whatever computations within MyTableModel::data?
? Because there's a lot more work to for visual computation that there is for mere model access! For example,
resizeColumnToContents()
is going to have to measure the font width of every string shown to decide how wide it is in order to line up.... That's why it may not be a great idea to show "thousands" of rows (with multiple columns) in a view, but up to you. -
You should not use QHeaderView::ResizeToContents in your views when there is a large amount of data - because it needs, as @JonB already said, to calculate all cell widths.
-
@Christian-Ehrlicher , @Joachim-W
As an observation.resizeColumnToContents()
is slow with a large table model. IIRC, in Windows at least when you double-click on a column-width-drag-resizer-line to make it size to widest shown, I think it always calculates only from those rows/columns which are visible in the current pane. If you scroll down you can still meet wider items, and have to double-click again.OTOH, I think the Qt
resizeColumnToContents()
calculates on all rows/columns in the view, regardless of viewport visibility.There will be a big speed difference between these two behaviours on large data. Would be nice if the Qt one could do the visible, fast one, maybe you have to override
resizeColumnToContents()
with your own code to implement? -
@JonB said in QAbstractItemModel: much time lost on nothing between beginResetModel() and endResetModel():
all rows/columns in the view, regardless of viewport visibility.
No :)
See https://doc.qt.io/qt-5/qheaderview.html#setResizeContentsPrecision
And if this is not enough you can overwrite QTableView::sizeHintForColumn() iirc. -
@Christian-Ehrlicher
Wow! Yep, good for you & QtThe default value is 1000
Special value 0 means that it will look at only the visible area.@Joachim-W
Try changing that value from 1,000 to 0 and see how it affects your speed situation? -
@Joachim-W Then please mark this topic as solved, thx.