ListView loaded by Loader directly causes sections to not update when model changed
Solved
QML and Qt Quick
-
Here is a "fun" one. I will be submitting a bug report:
import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15 Window { width: 640 height: 480 visible: true title: qsTr("ListView section header update") /* To cause the issue with sections not updating properly you need to scroll the list down a bit. listview1 not being inside an Item causes the problem */ function makeEntry(name, param, value){ let entry = { name: name, param: param, value_: value, } return entry } property var parammodel1: [ makeEntry("name 1", "section 1", "1"), makeEntry("name 2", "section 1", "2"), makeEntry("name 3", "section 1", "3"), makeEntry("name 4", "section 2", "4"), makeEntry("name 5", "section 2", "5"), makeEntry("name 6", "section 3", "6"), ] property var parammodel2: [ makeEntry("name 1", "section a", "1"), makeEntry("name 2", "section a", "2"), makeEntry("name 3", "section b", "3"), makeEntry("name 4", "section c", "4"), makeEntry("name 5", "section d", "5"), makeEntry("name 6", "section d", "6"), ] ListModel { id: parameters property var curmodel: parammodel1 onCurmodelChanged: changeModel(curmodel) Component.onCompleted: { //changeModel(curmodel) // can cause crash, different bug... } function changeModel(modellist){ clear() append(modellist) } } Rectangle { id: topitem anchors.top: parent.top width: parent.width height: 100 border.width: 1 Row { spacing: 20 Text { text: loader.item.objectName } Button { text: "swap model" onClicked: { if(parameters.curmodel == parammodel1){ parameters.curmodel = parammodel2 }else{ parameters.curmodel = parammodel1 } } } Button { text: "change view" onClicked: { if(loader.sourceComponent == listview1_comp){ loader.sourceComponent = listview2_comp }else{ loader.sourceComponent = listview1_comp } } } } } Loader { id: loader anchors.top: topitem.bottom anchors.bottom: parent.bottom width: parent.width / 2 sourceComponent: listview1_comp } Component { id: listview1_comp //Item { ListView { id: listview1 objectName: "listview1 broken" visible: true anchors.top: parent.top anchors.bottom: parent.bottom width: parent.width model: parameters currentIndex: 0 clip: true highlightFollowsCurrentItem: true snapMode: ListView.SnapToItem highlightMoveDuration: 100 highlight: Rectangle { z:10 color: "transparent" border.width: 2 border.color: "yellow" width: listview1.width height: 30 } highlightRangeMode: ListView.StrictlyEnforceRange preferredHighlightBegin: 30 preferredHighlightEnd: 30 + 20 interactive: true boundsBehavior: Flickable.StopAtBounds reuseItems: false cacheBuffer: 0 section.property: "param" section.delegate: Rectangle { width: listview1.width height: 30 color: "lightgreen" required property string section Text { text: section } } delegate: Rectangle { width: view.width height: 30 property var view: ListView.view Text { text: "%1 = %2".arg(name).arg(value_) } MouseArea { anchors.fill: parent onClicked: { view.currentIndex = index } } } //} } } Component { id: listview2_comp Item { // if listview is not loaded directly by loader then it works fine objectName: "listview2 okay" ListView { id: listview1 visible: true anchors.top: parent.top anchors.bottom: parent.bottom width: parent.width model: parameters currentIndex: 0 clip: true highlightFollowsCurrentItem: true snapMode: ListView.SnapToItem highlightMoveDuration: 100 highlight: Rectangle { z:10 color: "transparent" border.width: 2 border.color: "yellow" width: listview1.width height: 30 } highlightRangeMode: ListView.StrictlyEnforceRange preferredHighlightBegin: 30 preferredHighlightEnd: 30 + 20 interactive: true boundsBehavior: Flickable.StopAtBounds reuseItems: false cacheBuffer: 0 section.property: "param" section.delegate: Rectangle { width: listview1.width height: 30 color: "lightgreen" required property string section Text { text: section } } delegate: Rectangle { width: view.width height: 30 property var view: ListView.view Text { text: "%1 = %2".arg(name).arg(value_) } MouseArea { anchors.fill: parent onClicked: { view.currentIndex = index } } } } } } }
Sorry for not explaining. When the underlying model changes on the listview then the sections can get corrupted. Particularly you have to scroll a bit. This only occurs on the listview not wrapped inside an Item that is loaded by a loader.
-