Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-69245

QTreeView/QHeaderView: Incorrect behaviour when model changes layout

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P2: Important
    • None
    • 5.10.1
    • Widgets: Itemviews
    • None

    Description

      INTRODUCTION

      When data inside a model is being sorted, layoutAboutToBeChanged() and layoutChanged() signals should be emitted before and after sorting to let other components (e.g. views) react to these changes.

      However there seems to be a bug that occurs in the QTreeView-QHeaderView combination which causes incorrect updating of header's length on layout change and in consequence makes it impossible to restore a header's state from QByteArray. QTableView is not affected by this bug.

      DETAILS

      When QHeaderView's stretchLastSection is set to true and the last sections is currently streched (meaning all sections fit in the tree view) every update of model's layout causes incrementing of header's width. This is a left-most QtreeView on the screenshot with 2 columns.

      This bug does not occur when sections don't fit in the QTreeView even if strechLastSection is set to true (on the screenshot this the middle QTreeView with 10 columnns).

      This bug also never occurs when stretchLastSection is set to false (right-most QTreeView with 2 coluns).

      As described above QTreeView incorrectly icrements its size after every layout update when all sections fit in the view and strechLastSection is set to true. This results in a situation where QHeaderView's total width is greater then sections' combined width. Important negative side effect is that, after storing QHaderView's state in QByteArray, restoration is broken because of this length difference:

      // Inside bool QHeaderViewPrivate::read(QDataStream &in):
      if (sectionItemsLengthTotal != lengthIn)
      return false;
      

      I attach a simple project to test the problem. Every time you click update buttons, a TableModel::updateLayout() function is called that just emits layoutAboutToBeChanged() and layoutChanged() signals. It looks like these signals are connected to QHeaderViewPrivate::_q_sectionsAboutToBeChanged and QHeaderViewPrivate::_q_sectionsChanged respectively.

      // Inside QHeaderViewPrivate::_q_sectionsAboutToBeChanged:
      if (stretchLastSection && lastSectionLogicalIdx >= 0 && lastSectionLogicalIdx < sectionItems.count()) {
            const int visual = visualIndex(lastSectionLogicalIdx);
            if (visual >= 0 && visual < sectionItems.size()) {
                auto &itemRef = sectionItems[visual];
                if (itemRef.size != lastSectionSize) {
                    length += lastSectionSize - itemRef.size; // <<====
                    itemRef.size = lastSectionSize;
                }
            }
      }
      

      This code checks if strechLastSection is set to true and then it might change the header's width. Maybe there is some problem? However as I've written above this problem does not affect QTableView.

      IMPLICATIONS

      This bug breaks QHeaderView's state saving and restoring.

      WORKAROUND

      Do not use QHeaderView's strechLastSection with QTreeView if a model might change its contents.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            qt.team.quick.subscriptions Qt Quick and Widgets Team
            atomblender atomblender
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes