QAbstractTableModel.data() called on full data, outside displayed ones
-
Hi Qt Community,
I'm having trouble with my application calling the data access function (QAbstractTableModel.data(index, role)) multiple times on indexes that are out of display range.
My data is quite large (thousands of lines), and calling each and every cell multiple times (different roles) is not tractable.My questions are :
- why is the data(index,role) called when the QTableView is not showed at all ? Sometimes multiple times !
- why is it called on all indexes while only 30 lines are displayed when I finally display the QTableView ?
- is this to be expected with QAbstractTableModel+QTableView, or is it due to poor coding on my part (which I hope) ? Then where should I look ?
More details on my app and the problem as I see it :
- I have two tabs,
one with configuration : loading data from multiple files, updating the data content. No view is showed.
one with the QTableView : 30 rows are displayed - When I launch my app :
the system loads data (calling begin/endResetModel) multiple times
the configuration tab is displayed (no view of the model)
During call to MainWindow.show(), I can see that my whole data is called with DisplayRole on all rows, and this 2 times ! (I am still not displaying any view) - Then I switch to the "view" tab, containing the QTableView, for the first time
I can see that my whole data is called with DisplayRole on all rows, and this four times !
And right after, I can se that the 30 first rows are called with displayRole (which is expected)
Using the tableview slider calls data() on the corresponding new rows to be displayed (also as expected) - Then, each time I switch to config and back to display, the data() is called on all rows, twice !
- Each time I add a line (calling begin/endinsertRow), the whole data is read with data(displayRole)...
Looking for advices !
ThanksPS: I'm using Pyside2 (Qt for Python v5.13), but I guess the behavior is supposed to be similar to C++, and comments in C++ are welcome, I'll convert it to python.
-
Please provide a minimal, compilable example so we can see what may go wrong.
-
Thanks @Christian-Ehrlicher , I was cleaning my code block by block to be able to show a lighter version here, and I started to be pretty sure the "problem" was comming from Qt as I had deleted almost every complicated thing from my code.
Then I found these lines :
self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.table_view.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.table_view.horizontalHeader().setStretchLastSection(True)
They are the ones responsible, which acutally makes sense, Qt has to read all the data to find the max size of elements.
Results of my trials: number of full data access by state :
Open App / Show TableView for the 1st time / show-hide TableView again / Resize window H Resize2Contents : 1 2 1 Crazy V Resize2Contents : 0 3 1 Crazy H+V Resize2Contents : 2 4 2 Crazy H+V + HStretchLast : 2 6 2 Crazy HStretchLast only : 0 0 0 0
In the end this was totally unrelated to my model, *ResetModel, ... but to display options...
I hope this will save time to people in the future, who will think twice before using these functions that seem harmless !
-
A good example on why a simple reproducer is a good starting point.
See also QHeaderView::setResizeContentsPrecision - it may help you if you need to use this resize mode./edit: and please mark the topic as solved, thx.
-
@Christian-Ehrlicher Thanks again, exactly what I needed.
Still some strange behavior though :self.table_view.horizontalHeader().setResizeContentsPrecision(0) self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
Works fine if I force the view tab to be selected at startup. Else (maybe because it doesnt know how many rows will be displayed), it runs through the entire data.
On the other hand, the verticalHeader equivalent lines still process the whole data. Any idea why ?
For now I will set it to Fixed. -
'Special value 0 means that it will look at only the visible area.'
-
Hi,
@Christian-Ehrlicher cited the content of the documentation of the function.
-
Pardon for posting in this old thread, but I found it during digging inside the same problem.
First, I thought that I found the solution here -setResizeContentsPrecision(0)
. But next, I tried to doself.view.verticalHeader().setResizeContentsPrecision(0) self.view.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
and it fetches all rows... Should
setResizeContentsPrecision
work for vertical header also?
If not - is there any way to have rows of different height in QTableView without reading whole table data? -
@StarterKit said in QAbstractTableModel.data() called on full data, outside displayed ones:
If not - is there any way to have rows of different height in QTableView without reading whole table data?
No because then the size of the scrollbar can not be determined.
-
@Christian-Ehrlicher , yes, I see your point. But this is valid if we calculate scroll bar position based on row geometry. As alternative - we may calculate scroll bar size/position based on row count - it will give neglegible error for tables with tens of rows (and almost 0 error for large tables with hunderds -thousands rows...). I think it might be a useful feature of QTableVew/QHeaderView...
-
Feel free to provide a patch for it :)
-
@Christian-Ehrlicher said in QAbstractTableModel.data() called on full data, outside displayed ones:
Feel free to provide a patch for it :)
Ok, will read a bit about how to build Qt from source and make changes. Have never done it before.
-
@StarterKit Since you would like to create a patch (that's cool, thanks), don't try to build the whole of Qt since your patch is located in qtbase, you can just build that module and go hacking.
-
@SGaist thanks for the advice. I'll try to do it in spare time.
Right now I decided to play with
QTableView::setRowHeight()
. It appears to do the job quite well, but code structure looks ugly.
But looking how fast it does the job I really start thinking that it is a bug thatsetResizeContentsPrecision(0)
doesn't work for vertical header.I.e. as a first test I called
setRowHeight()
fromdata()
method of the model. This method is called many times for different roles and columns. And even in these non-optimal conditions it works well as it is called for visible rows only. And there are no problems with scrollbar at all - it works as it should. I assume withsetResizeContentsPrecision(0)
it may do the same or similar action but with only one call todata()
forSizeHintRole
.I reported QTBUG-100818 first of all for documentation, but mentioned there my doubts.