Object List Model Example

Tags: Android

A list of QObject values can also be used as a model. A list[QObject,] provides the properties of the objects in the list as roles.

The following application creates a DataObject class with Property values that will be accessible as named roles when a list[DataObject,] is exposed to QML:

Object List Model Screenshot

Download this example

from __future__ import annotations

from pathlib import Path
import sys
from PySide6.QtCore import QObject
from PySide6.QtGui import QGuiApplication
from PySide6.QtQuick import QQuickView
from PySide6.QtQmlFeatures import auto_properties, watch, Change

# This example illustrates exposing a list of QObjects as a model in QML


# @auto_properties turns the plain "self.name = ..." / "self.color = ..."
# assignments into real Q_PROPERTYs with nameChanged/colorChanged notify
# signals, so QML can read them as model roles and write them back. The
# @watch method then runs whenever the color is changed from QML.
@auto_properties
class DataObject(QObject):

    def __init__(self, name, color, parent=None):
        super().__init__(parent)
        self.name = name
        self.color = color

    @watch("color")
    def on_color_changed(self, change: Change):
        print(f"{self.name}: color {change.old} -> {change.new}")


if __name__ == '__main__':
    app = QGuiApplication(sys.argv)

    dataList = [DataObject("Item 1", "red"),
                DataObject("Item 2", "green"),
                DataObject("Item 3", "blue"),
                DataObject("Item 4", "yellow")]

    view = QQuickView()
    view.setResizeMode(QQuickView.ResizeMode.SizeRootObjectToView)
    view.setInitialProperties({"model": dataList})

    qml_file = Path(__file__).parent / "view.qml"
    view.engine().addImportPath(Path(__file__).parent)
    view.loadFromModule("ObjectListModel", "Main")
    view.show()

    r = app.exec()
    del view
    sys.exit(r)
import QtQuick
import QtQuick.Controls

ListView {
    id: listview
    width: 200; height: 320
    required model
    ScrollBar.vertical: ScrollBar { }

    delegate: Rectangle {
        id: row
        width: listview.width; height: 25

        required property string name
        required property var modelData

        // Explicit binding so the Rectangle tracks modelData.colorChanged
        // directly. A plain Python list of QObjects never emits dataChanged()
        // This would have not been needed if 'dataList' was done through
        // a QAbstractListModel subclass, which emits dataChanged() on every
        // role update.
        color: modelData.color

        Text { text: parent.name }

        // Click a row to recolor it. Writing modelData.color from QML runs
        // the DataObject's @watch("color") callback on the Python side, and
        // emits colorChanged so this binding refreshes.
        TapHandler {
            onTapped: {
                const palette = ["red", "green", "blue", "yellow", "magenta"]
                const next = (palette.indexOf(row.modelData.color) + 1) % palette.length
                row.modelData.color = palette[next]
            }
        }
    }
}
module ObjectListModel
Main 1.0 Main.qml