Can one add a complex type item to ListModel?

2019-07-14 02:23发布

I would like to have a ListModel-like structure to display inputs of a simple state machine. Each input might consist of several strings/ints. So I need each item of the ListModel to be able to store a list of data (strings with names of the input's parameters, or dictionaries with strings etc). At the moment I cannot append an item with a list property to a ListModel.

So the ListModel looks like this:

ListView {
    anchors.fill: parent

    model: ListModel {
        id: listModel
    }

    delegate: Text {
        text: inputs[0]['name']
    }
}

And when the state changes I want to update the model and append elements like this:

var state = {
    name: "abcd",
    inputs: [{name: 'a'}, {name: 'b'}, {name: 'c'}]
}
listModel.append(state);

Current version of the code returns error TypeError: Cannot read property 'name' of undefined. It does not see the list.

According to this question there might be issues with using lists in the items of ListModel. But it seems irrelevant to my case. Maybe I need to use lists and dicts differently in QML, maybe I had to write text: inputs[0].name in delegate (which I tried) or something else (suggestions?).

Could someone suggest how to make a more or less complex item (basically, it is standard JSON) in a ListModel? It is not clear, since documentation and blogs/questions deal with strings all the time. Is there some helpful documentation which I missed? What are good practices to do it in QML? Should I use some custom objects?

1条回答
The star\"
2楼-- · 2019-07-14 02:39

List data can be added to a ListElement, according to the documentation and as you correctly did in your imperative code. However, nested roles are not really arrays. They are ListModels themselves. That's because, by design, QML does not produce a notification if an element of an array changes, which would be a show-stopper in a model-view-delegate setting.

Since the nested role is a model, you can use model's functions. For instance, this example works fine:

import QtQuick 2.5
import QtQuick.Window 2.2

Window {
    id: window
    width: 600
    height: 400
    visible: true

    ListView {
        anchors.fill: parent

        model: ListModel {
            id: listModel
        }

        delegate: Text {
            text: name + inputs.get(index % inputs.count).name  // accessing the inner model
        }
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            var state = {
                name: "abcd",
                inputs: [{name: 'a'}, {name: 'b'}, {name: 'c'}]
            }
            listModel.append(state);
        }
    }
}

According to your question, the input is plain JSON. In that case, consider the usage of JSONListModel in place of ListModel. It exposes a set of API which matches XMLListModel, via JSONPath, and could possibly represent the perfect solution for your scenario.

查看更多
登录 后发表回答