ListView не обновляется при изменении модели строкового массива

My ListView не показывает новые записи в моей модели при их добавлении.

Когда открывается диалоговое окно, я копирую QStringList из элемента C ++ в свойство Qml. Затем пользователь изменяет массив, используя предоставленные элементы управления (добавление, изменение, удаление).

К сожалению, ListView не обновляется, когда я изменяю свойство. Свойство изменено правильно (как видно из результатов отладки).

Как сделать так, чтобы ListView обновлялся автоматически с помощью привязки данных?

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
            }
        }
    }
}

person feedc0de    schedule 12.07.2017    source источник


Ответы (2)


Причина в том, что отсутствует thingsChanged-сигнал при использовании функции для изменения things. Ссылка, хранящаяся в things, останется неизменной, что бы вы ни делали.

Для моделей данных, таких как ListModel, это то же самое, но существуют специальные сигналы многие из которых используются, чтобы указать любому представлению, что оно должно обновлять его содержимое.

Если вам отчаянно нужно использовать массивы, вам нужно вызывать thingsChanged() вручную всякий раз, когда вы что-то меняете в содержимом массивов. Но поскольку это указывает только на то, что изменился весь массив, одна из основных сильных сторон View недействительна - способность изменять только то, что было изменено.

Когда View реагирует на thingsChanged-сигнал, он уничтожает все текущие делегаты, а затем воссоздает их снова, независимо от того, изменится ли что-нибудь.

Если вы используете ListModel или QAbstractItemModel-потомок, View может вставлять отдельные экземпляры новых делегатов, удалять или изменять их.

person derM    schedule 12.07.2017

Замените массив реальной ListModel. Используйте функцию append!

Button {
            Layout.fillWidth: true
            text: qsTr("Clear");
            onPressed: {
                model.append({"data": theTextField.text})
            }
        }

и в главном блоке ListModel {id: model}

person Kombinator    schedule 12.07.2017