Details
-
Bug
-
Resolution: Fixed
-
P2: Important
-
None
-
5.10.1
-
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.