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"?
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
}
}
}
}