Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 !
    Thanks

    PS: 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.


  • Qt Champions 2019

    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 !


  • Qt Champions 2019

    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.


  • Qt Champions 2019

    'Special value 0 means that it will look at only the visible area.'



  • Someone should add a note to the documentation for those functions - its pathetically sparse and there should be ample warning.


  • Lifetime Qt Champion

    Hi,

    @Christian-Ehrlicher cited the content of the documentation of the function.


Log in to reply