Search code examples
qtqmlqt5qtquick2qtquickcontrols2

ListView does not refresh when string array model changes


My ListView doesnt show new entries in my model when they are added.

When a dialog opens I copy a QStringList from a C++ item into a Qml property. The user then modifies the array using provided controls (add, modify, remove).

Sadly the ListView doesnt update when I modify the property. The property is modified correctly (as seen by debugging output).

How can I make the ListView updating automatically using data binding?

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    property var things

    Component.onCompleted: things = [] // normally retrieved from C++ QStringList

    ColumnLayout {
        anchors.fill: parent

        RowLayout {
            Layout.fillWidth: true

            TextField {
                Layout.fillWidth: true
                id: theTextField
            }

            Button {
                Layout.fillWidth: true
                text: qsTr("Append")
                onPressed: {
                    things.push(theTextField.text)
                    console.log(things)
                }
            }

            Button {
                Layout.fillWidth: true
                text: qsTr("Remove")
                onPressed: {
                    var index = things.indexOf(theTextField.text)
                    if(index == -1)
                        console.warn('Not found!')
                    else
                        things.splice(index, 1)
                    console.log(things)
                }
            }

            Button {
                Layout.fillWidth: true
                text: qsTr("Clear");
                onPressed: {
                    things = [];
                    console.log(things)
                }
            }
        }

        ListView {
            id: listView

            Layout.fillWidth: true
            Layout.fillHeight: true
            model: things
            delegate: Label {
                text: modelData
            }
        }
    }
}

Solution

  • The reason for that is, that there is no thingsChanged-signal when using a function to modify the things. The reference stored in things will stay the same, no matter what you do.

    For the data models such as ListModel this is the same, but there exist special signals many of which are used to indicate to any view, that it should update it's content.

    If you desperately need to use arrays, you need to call thingsChanged() manually, whenever you changed something to the arrays content. But as this indicates only that the whole array has changed, one of the major strengths of a View are void - the ability to change only what has been changed.

    When a View reacts to a thingsChanged-signal, it will destroy all current delegates and then recreate them again, no matter whether anything will be different.

    If you use a ListModel or QAbstractItemModel-descendent, the View can insert single instances of new delegates, remove or alter them.