Search code examples
pythonqtlistviewpyqtqml

QML ListView sections from the code


I am unable to implement listview with sections. I've successfully repeated an example from Qt documentation but there is ListModel used which works okay, but not a var.

How it works with example:

ListView {
    width: 100
    height: 100
    id: listview
    model: ListModel {
        id: animalsModel
        ListElement { name: "Ant"; size: "Tiny" }
        ListElement { name: "Flea"; size: "Tiny" }
        ListElement { name: "Parrot"; size: "Small" }
        ListElement { name: "Guinea pig"; size: "Small" }
        ListElement { name: "Rat"; size: "Small" }
        ListElement { name: "Butterfly"; size: "Small" }
        ListElement { name: "Dog"; size: "Medium" }
        ListElement { name: "Cat"; size: "Medium" }
        ListElement { name: "Pony"; size: "Medium" }
        ListElement { name: "Koala"; size: "Medium" }
        ListElement { name: "Horse"; size: "Large" }
        ListElement { name: "Tiger"; size: "Large" }
        ListElement { name: "Giraffe"; size: "Large" }
        ListElement { name: "Elephant"; size: "Huge" }
        ListElement { name: "Whale"; size: "Huge" }
    }

    delegate: Text { text: name; font.pixelSize: 18 }

    section.property: "size"
    section.criteria: ViewSection.FullString
    section.delegate: Component {
        id: sectionHeading
        Rectangle {
            width: container.width
            height: childrenRect.height
            color: "lightsteelblue"

            Text {
                text: section
                font.bold: true
                font.pixelSize: 20
            }
        }
    }
}

GUI qt example

But when I try to use some model from the code (in my case it is a QVariant from PyQt5) it does not work at all:

ListView {
    width: 100
    height: 100
    id: listview
    property var m: [
        {
            name: "Animal",
            size: "Big"
        },
        {
            name: "Dog",
            size: "Small"
        },
        {
            name: "Cat",
            size: "Small"
        }
    ]
    model: m

    delegate: Text { text: modelData.name; font.pixelSize: 18 }

    section.property: "modelData.size"
    section.criteria: ViewSection.FullString
    section.delegate: Component {
        id: sectionHeading
        Rectangle {
            width: container.width
            height: childrenRect.height
            color: "lightsteelblue"

            Text {
                text: section
                font.bold: true
                font.pixelSize: 20
            }
        }
    }
}

The reason I choose var here because there is not any other method to receive a model from Python , so any list or map from python needs to be wrapped as QVariant.


Solution

  • From Qt documentation:

    model : model

    This property holds the model providing data for the list. The model provides the set of data that is used to create the items in the view. Models can be created directly in QML using ListModel, XmlListModel or VisualItemModel, or provided by C++ model classes. If a C++ model class is used, it must be a subclass of QAbstractItemModel or a simple list.

    So you cannot provide an array as a model, it should be one of the objects above. You can create such model and access it from Python code to add/remove items.

    ListView {
        width: 100
        height: 100
        id: listview
        delegate: Text { text: name; font.pixelSize: 18 }
    
        model: ListModel { id: listModel }
    
        section.property: "size"
        section.criteria: ViewSection.FullString
        section.delegate: Component {
            id: sectionHeading
            Rectangle {
                width: container.width
                height: childrenRect.height
                color: "lightsteelblue"
    
                Text {
                    text: section
                    font.bold: true
                    font.pixelSize: 20
                }
            }
        }
    
        function callFromPython {
            listModel.append({name: "Animal",size: "Big"});
            listModel.append({name: "Dog",size: "Small"});
            listModel.append({name: "Cat",size: "Small"});
        }
    }