I have a ListView in QML and want to populate it with data from a AbstractListModel that I created in Python.
AbtractListModel.py (I removed methods like rowCount() to keep the example lucid)
class StudentModel(QAbstractListModel): def __init__(self) super().__init() self.studentList = [] self.studentList.append(Student("Peter", 22) def data(self, index: QtCore.QModelIndex, role: int = ...) -> typing.Any: if role == QtCore.Qt.DisplayRole: return self.studentList[index] return None
Student.py
class Student(object): name = "" age = 0 def __init__(self, name, age): self.name = name self.age = age
ListView.qml
ListView { model: studentModel delegate: Rectangle { Text{ text: #name } Text{ text: #age } } }
How can I access name and age of a student in the delegate to show them where I used “#name” and “#age”?
Advertisement
Answer
At a minimum you must implement the rowCount, data and roleNames methods of the QAbstractListModel:
from __future__ import annotations import os import sys import typing from dataclasses import dataclass, fields from pathlib import Path from PySide6.QtCore import ( QAbstractListModel, QByteArray, QCoreApplication, QModelIndex, QObject, Qt, QUrl, ) from PySide6.QtGui import QGuiApplication from PySide6.QtQml import QQmlApplicationEngine CURRENT_DIRECTORY = Path(__file__).resolve().parent @dataclass class Student: name: str = "" age: int = 0 class StudentModel(QAbstractListModel): def __init__(self, parent=QObject | None) -> None: super().__init__() self._studend_list = [] self._studend_list.append(Student("Peter", 22)) def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> typing.Any: if 0 <= index.row() < self.rowCount(): student = self._studend_list[index.row()] name = self.roleNames().get(role) if name: return getattr(student, name.decode()) def roleNames(self) -> dict[int, QByteArray]: d = {} for i, field in enumerate(fields(Student)): d[Qt.DisplayRole + i] = field.name.encode() return d def rowCount(self, index: QModelIndex = QModelIndex()) -> int: return len(self._studend_list) def add_student(self, student: Student) -> None: self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount()) self._studend_list.append(student) self.endInsertRows() def main() -> None: app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() student_model = StudentModel() engine.rootContext().setContextProperty("studentModel", student_model) filename = os.fspath(CURRENT_DIRECTORY / "main.qml") url = QUrl.fromLocalFile(filename) def handle_object_created(obj: QObject | None, obj_url: QUrl) -> None: if obj is None and url == obj_url: QCoreApplication.exit(-1) engine.objectCreated.connect(handle_object_created, Qt.QueuedConnection) engine.load(url) student_model.add_student(Student("wileni", 23)) sys.exit(app.exec()) if __name__ == "__main__": main()
import QtQuick import QtQuick.Controls ApplicationWindow { id: root width: 640 height: 480 visible: true ListView { model: studentModel anchors.fill: parent delegate: Row { Text { text: model.name } Text { text: model.age } } } }