Quantcast
Channel: Active questions tagged qtquick2 - Stack Overflow
Viewing all articles
Browse latest Browse all 107

Accessing Qt Quick ListView model from the nested elements in a custom delegate

$
0
0

I'm having difficulty finding the idiomatic way to access ListView's model from its delegate in QML.

Consider the following fairly simple custom delegate that supports a checkbox near the item and tracks the currently chosen item in the list. (To clarify: the checkbox selection and list selection are independent.)

Rectangle {    id: wrapper    required property int index    required property string name    required property bool selected    width: ListView.view.width    height: 32    radius: 3    color: "transparent"    Label {        anchors.left: parent.left        anchors.right: selectedBox.left        anchors.verticalCenter: parent.verticalCenter        anchors.margins: 5        text: wrapper.name        MouseArea {            anchors.fill: parent            onClicked: wrapper.ListView.view.currentIndex = wrapper.index        }    }    CheckBox {        id: selectedBox        anchors.right: parent.right        anchors.verticalCenter: parent.verticalCenter        checked: wrapper.selected        onToggled: wrapper.ListView.view.model.setProperty(wrapper.index, "selected", checked)    }}

This is working code though making onToggle work was particularly troublesome. In the end I found this magical ListView.view.model rune to access the underlying model in the Qt docs and figured out I can prepend the delegate ID to it.

It seems to be too verbose to be correct for the task delegates were created for though.

The majority of examples online hardcode this value to a particular model which violates Delegate and Model concept separation and I don't want to go this route. I also saw just model being used (the last listing in the linked docs), but it doesn't work for me even if I require property ListModel model for it in the delegate.

So the question is whether there is a simpler way.

Here's a sample list and model to test the delegate:

ListView {    // ...    model: myModel    delegate: myDelegate    highlight: Rectangle {        color: "lightsteelblue"        radius: 5    }    focus: true}ListModel {    id: myModel    ListElement {        name: "Item 1"        selected: false    }    ListElement {        name: "Item 2"        selected: false    }}

EDIT. There are actually two good solutions, a short one and a more verbose but foolproof.

I could drop all required property declarations and use

    Label {        // ...        text: name        // ...    }    CheckBox {        // ...        checked: selected        onToggled: selected = checked    }

I couldn't come to this solution because my initial design had the model property named checked and then it's kind of unclear how this approach can be applied then.

In case of name collisions it's possible to make a required model property and then it's bound to the corresponding row of the list model:

Rectangle {    id: wrapper    required property var model    // ...    Label {        // ...        text: model.name        // ...    }    CheckBox {        // ..        checked: model.selected        onToggled: model.selected = checked    }}

The second options seems to be preferable, so I'll go with it.


Viewing all articles
Browse latest Browse all 107

Trending Articles