Проблема
Я пытаюсь отобразить очень простые 2D-данные в Qt Quick, используя QML TableView и Qt для Python/PySide6 . Вот пример того, что я хочу создать:
На создание этой таблицы в LabVIEW у меня ушло всего несколько минут. Однако я совершенно не понимаю, как правильно это сделать в QML и Python, используя одноэлементный подход.
Что я читал
- для Qt 6.7
Код: Выделить всё
QStandardItemModel - для Qt для Python 6.7
Код: Выделить всё
QStandardItemModel - Тип QML для Qt 6.7
Код: Выделить всё
TreeView - Бесчисленное количество сообщений на StackOverflow и форумах, где я безуспешно пытался воспроизвести предполагаемые решения.
Пример на чистом QML, который работает
Официальная документация, к сожалению, выделяет простейший случай, в котором модель определена исключительно в 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: TableModel {
TableModelColumn {
display: "Timestamp"
}
TableModelColumn {
display: "Logger"
}
TableModelColumn {
display: "Level"
}
TableModelColumn {
display: "Message"
}
rows: [
{
"Timestamp": "today",
"Logger": "root",
"Level": "DEBUG",
"Message": "This is a debug message"
},
{
"Timestamp": "today",
"Logger": "root",
"Level": "INFO",
"Message": "This is an info message"
}
]
}
delegate: Rectangle {
border.width: 1
clip: true
Text {
text: display
anchors.centerIn: parent
}
}
}
}

Конечно, столбец сообщений необходимо сделать шире, и я не уверен, как с помощью этой настройки отображать имена заголовков, но это, по крайней мере, показывает, что остальная часть QML верна, и проблема связана с моей моделью.
QML плюс Python не работает
Следующий код должен быть очень близко к работе, но это не так. Я не знаю, как это изменить, чтобы таблица отображалась так, как ожидалось.Код: Выделить всё
// 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())
Вот набор закомментированных кодов, которые я пробовал: среди многих других перестановок. Это просто представление различных фрагментов того, что я пробовал в коде и пытался лучше понять.
Код: Выделить всё
# table.setItemRoleNames(
# {i: FIELD_NAMES[i].encode() for i in range(len(FIELD_NAMES))}
# )
# for row_index, line in enumerate(lines):
# for column_index, key in enumerate(FIELD_NAMES):
# item = QStandardItem(str(line[key]))
# table.setItem(row_index, column_index, item)
# for line in lines:
# row = QStandardItem()
# for role_index, key in enumerate(FIELD_NAMES):
# row.setData(str(line[key]), Qt.ItemDataRole + role_index)
# table.appendRow(row)
# for line in lines:
# row = QStandardItem()
# for role_index, key in enumerate(FIELD_NAMES):
# row.appendColumn([QStandardItem(str(line[key]))])
# table.appendRow(row)
Вопросы
- [Основной] Каков самый простой и прямой способ отображения 2D-данных в QML TableView из QStandardItemModel в Python? Что не так с моей попыткой, описанной выше?
- [Вторичное] Куда мне обратиться, чтобы узнать об этом больше? Официальная документация в этом отношении почти бесполезна, и поэтому я застрял в экспериментальном режиме, просто пробуя что-то. Qt также плохо работает с QML и одноэлементным подходом в Python, что увеличивает сложность отладки.
Подробнее здесь: https://stackoverflow.com/questions/787 ... -tableview