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)
JavaScript
x
11
11
1
class StudentModel(QAbstractListModel):
2
def __init__(self)
3
super().__init()
4
self.studentList = []
5
self.studentList.append(Student("Peter", 22)
6
7
def data(self, index: QtCore.QModelIndex, role: int = ) -> typing.Any:
8
if role == QtCore.Qt.DisplayRole:
9
return self.studentList[index]
10
return None
11
Student.py
JavaScript
1
8
1
class Student(object):
2
name = ""
3
age = 0
4
5
def __init__(self, name, age):
6
self.name = name
7
self.age = age
8
ListView.qml
JavaScript
1
9
1
ListView {
2
model: studentModel
3
4
delegate: Rectangle {
5
Text{ text: #name }
6
Text{ text: #age }
7
}
8
}
9
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:
JavaScript
1
84
84
1
from __future__ import annotations
2
3
import os
4
import sys
5
import typing
6
from dataclasses import dataclass, fields
7
from pathlib import Path
8
9
from PySide6.QtCore import (
10
QAbstractListModel,
11
QByteArray,
12
QCoreApplication,
13
QModelIndex,
14
QObject,
15
Qt,
16
QUrl,
17
)
18
from PySide6.QtGui import QGuiApplication
19
from PySide6.QtQml import QQmlApplicationEngine
20
21
22
CURRENT_DIRECTORY = Path(__file__).resolve().parent
23
24
25
@dataclass
26
class Student:
27
name: str = ""
28
age: int = 0
29
30
31
class StudentModel(QAbstractListModel):
32
def __init__(self, parent=QObject | None) -> None:
33
super().__init__()
34
self._studend_list = []
35
self._studend_list.append(Student("Peter", 22))
36
37
def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> typing.Any:
38
if 0 <= index.row() < self.rowCount():
39
student = self._studend_list[index.row()]
40
name = self.roleNames().get(role)
41
if name:
42
return getattr(student, name.decode())
43
44
def roleNames(self) -> dict[int, QByteArray]:
45
d = {}
46
for i, field in enumerate(fields(Student)):
47
d[Qt.DisplayRole + i] = field.name.encode()
48
return d
49
50
def rowCount(self, index: QModelIndex = QModelIndex()) -> int:
51
return len(self._studend_list)
52
53
def add_student(self, student: Student) -> None:
54
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
55
self._studend_list.append(student)
56
self.endInsertRows()
57
58
59
def main() -> None:
60
app = QGuiApplication(sys.argv)
61
62
engine = QQmlApplicationEngine()
63
64
student_model = StudentModel()
65
engine.rootContext().setContextProperty("studentModel", student_model)
66
67
filename = os.fspath(CURRENT_DIRECTORY / "main.qml")
68
url = QUrl.fromLocalFile(filename)
69
70
def handle_object_created(obj: QObject | None, obj_url: QUrl) -> None:
71
if obj is None and url == obj_url:
72
QCoreApplication.exit(-1)
73
74
engine.objectCreated.connect(handle_object_created, Qt.QueuedConnection)
75
engine.load(url)
76
77
student_model.add_student(Student("wileni", 23))
78
79
sys.exit(app.exec())
80
81
82
if __name__ == "__main__":
83
main()
84
JavaScript
1
29
29
1
import QtQuick
2
import QtQuick.Controls
3
4
ApplicationWindow {
5
id: root
6
7
width: 640
8
height: 480
9
visible: true
10
11
ListView {
12
model: studentModel
13
anchors.fill: parent
14
15
delegate: Row {
16
Text {
17
text: model.name
18
}
19
20
Text {
21
text: model.age
22
}
23
24
}
25
26
}
27
28
}
29