Reputation: 853
I am trying to display very simple 2D data in Qt Quick using a QML TableView
and Qt for Python / PySide6. Here is an example of what I am looking to create:
In the following code, I have exposed a singleton object to QML which provides a QStandardItemModel
as a QObject
property, but have been unable to get anything to display. What is wrong with my attempt?
// Main.qml
import QtQuick
import QtQuick.Window
import QtQuick.Layouts
import QtQuick.Controls
import Qt.labs.qmlmodels
import com.simplified
Window {
width: 740
height: 540
visible: true
title: "Python log viewer"
TableView {
id: log
anchors.fill: parent
columnSpacing: 1
rowSpacing: 1
clip: true
model: Simplified.log
delegate: Rectangle {
border.width: 1
clip: true
Text {
text: display
anchors.centerIn: parent
}
}
}
}
# main.py
QML_IMPORT_NAME = "com.simplified"
QML_IMPORT_MAJOR_VERSION = 1
# Core dependencies
from pathlib import Path
import sys
# Package dependencies
from PySide6.QtCore import QObject, Signal, Property, Qt
from PySide6.QtGui import QGuiApplication, QStandardItemModel, QStandardItem
from PySide6.QtQml import QQmlApplicationEngine, QmlElement, QmlSingleton
LOG_ENTRIES = [
{
"Timestamp": "2024-07-01 19:16:03.326",
"Name": "root.child",
"Level": "DEBUG",
"Message": "This is a debug message",
},
{
"Timestamp": "2024-07-01 19:16:03.326",
"Name": "root.child",
"Level": "INFO",
"Message": "This is an info message",
},
]
FIELD_NAMES = ["Timestamp", "Name", "Level", "Message"]
@QmlElement
@QmlSingleton
class Simplified(QObject):
log_changed = Signal()
def __init__(self) -> None:
super().__init__()
_ = self.log
self.log_changed.emit()
@Property(QStandardItemModel, notify=log_changed)
def log(self):
lines = LOG_ENTRIES
table = QStandardItemModel(len(lines), len(FIELD_NAMES))
table.setHorizontalHeaderLabels(FIELD_NAMES)
for line in lines:
row = [QStandardItem(str(line[key])) for key in FIELD_NAMES]
table.appendRow(row)
return table
if __name__ == "__main__":
application = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
qml_file = Path(__file__).resolve().parent / "qml" / "Main.qml"
engine.load(qml_file)
if not engine.rootObjects():
sys.exit(-1)
engine.singletonInstance("com.simplified", "Simplified")
sys.exit(application.exec())
Upvotes: -1
Views: 154
Reputation: 4732
You need to store the model. The QML TableView will not own the model, like the QAbstractItemView
derived classes. The returned model from the Simplified.log()
will be destroyed in the event loop, after the QML implementation of the TableView accesses it several times. Check the lifecycle of the models in the official examples.
Also, you specified the type of the Simplified.log
property as the QStandardItemModel
, but the property type dispatching implementation of the QML engine doesn't know the QStandardItemModel
as a property type because it's not registered by default. See the reference such as The QML Type System and Data Type Conversion.
The following is the example of the fixed code.
@QmlElement
@QmlSingleton
class Simplified(QObject):
log_changed = Signal()
def __init__(self):
super().__init__()
self.model = None
@Property(QObject, notify=log_changed)
def log(self):
if self.model is None:
self.model = model = QStandardItemModel()
for line in LOG_ENTRIES:
row = [QStandardItem(str(line[key])) for key in FIELD_NAMES]
model.appendRow(row)
return self.model
Upvotes: -1