[英]QT/QML Data Model
I want to create a Qt data model with a structure like below to use in Python and QML. If any values or keys are changed, added, or deleted in Python or QML I would need the values to be updated on the other side (QML or Python).我想创建一个 Qt 数据 model,其结构如下所示,用于 Python 和 QML。如果在 Python 或 QML 中更改、添加或删除了任何值或键(我需要在另一侧更新 QML 值)或蟒蛇)。 This would ideally be the model used in a ListView and I would only display certain fields for the ListView.
理想情况下,这将是 ListView 中使用的 model,我只会显示 ListView 的某些字段。 But I would use this data model to store all my information.
但我会使用这个数据 model 来存储我所有的信息。 When a test is performed for memory in Python I would want to write that test log information to this data model and display that in QML. I have read about QAbstractListModel, but I am unsure if I can make nested objects or lists and whether they would update automatically or not.
当在 Python 中对 memory 执行测试时,我想将该测试日志信息写入此数据 model 并在 QML 中显示。我已经阅读了 QAbstractListModel,但我不确定我是否可以制作嵌套对象或列表以及它们是否会自动更新与否。
System: {
Processor: {
name: 'Processor',
description: 'Intel i7 6600k',
iconSource: '/resources/images/chip.svg',
progressValue: 100,
pageSource: '/resources/qml/Processor.qml',
details: {
"badge": "Intel® Core i5 processor",
"cache": "6144 KB",
"clock": "4200000"
}
testLog: [
'Starting Cpu Test',
'Detected Intel CPU',
'Performing intense calculations',
'Processing calculations still',
'Cleaning up',
'Test Passed'
]
}
Memory: {
name: 'Memory',
description: 'Kingston 16GB DDR3',
iconSource: '/resources/images/ram.svg',
progressValue: 50,
pageSource: '/resources/qml/Processor.qml',
details: {
"device_locator_string": "ChannelB-DIMM1",
"device_set": 0,
"error_handle": 65534,
"extended_size": 0,
"form_factor": "Unknown"
},
testLog: [
'Starting Memory Test',
'Detected 2 x RAM modules',
'Performing intense calculations',
'Processing calculations still',
'Cleaning up',
'Test Failed'
]
}
}
There are several options in this case such as:在这种情况下有几种选择,例如:
Create a model based on QAbstractItemModel where you provide the properties through roles.基于 QAbstractItemModel 创建一个 model,您可以在其中通过角色提供属性。
Create a QObject Device that has the desired properties as qproperties and expose it through a qproperty associated with a signal from another QObject, the QObject Device list and use that list as a model.创建一个 QObject 设备,它具有所需的属性作为 qproperties,并通过与来自另一个 QObject 的信号关联的 qproperty 公开它,QObject 设备列表并将该列表用作 model。
Create a model as a QAbstractListModel (or QStandardItemModel) and expose the QObject through a role.创建一个 model 作为 QAbstractListModel(或 QStandardItemModel)并通过角色公开 QObject。
Create a QObject that exposes a list of QObjects Device through ListProperty.创建一个 QObject,通过 ListProperty 公开 QObjects Device 列表。
In this case I have chosen the first option for a demo:在这种情况下,我选择了第一个演示选项:
main.py主程序
from dataclasses import dataclass
import sys
from typing import Callable
from PySide2.QtCore import (
Property,
QCoreApplication,
QObject,
QVariantAnimation,
Qt,
QUrl,
)
from PySide2.QtGui import QGuiApplication, QStandardItem, QStandardItemModel
from PySide2.QtQml import QQmlApplicationEngine
@dataclass
class item_property:
role: int
function: Callable = None
def __call__(self, function):
self.function = function
return self
class item_property_impl(property):
def __init__(self, role, function):
super().__init__()
self._role = role
self._function = function
def __get__(self, obj, type=None):
if obj is None:
return self
if hasattr(obj, "_initial"):
obj.setData(self._function(obj), self._role)
delattr(obj, "_initial")
return obj.data(self._role)
def __set__(self, obj, value):
obj.setData(value, self._role)
class ItemMeta(type(QStandardItem), type):
def __new__(cls, name, bases, attrs):
for key in attrs.keys():
attr = attrs[key]
if not isinstance(attr, item_property):
continue
new_prop = item_property_impl(attr.role, attr.function)
attrs[key] = new_prop
if not hasattr(cls, "attrs"):
cls._names = []
cls._names.append(key)
obj = super().__new__(cls, name, bases, attrs)
return obj
def __call__(cls, *args, **kw):
obj = super().__call__(*args, **kw)
obj._initial = True
for key in cls._names:
getattr(obj, key)
return obj
class Item(QStandardItem, metaclass=ItemMeta):
pass
keys = (b"name", b"description", b"icon", b"progress", b"source", b"details", b"log")
ROLES = (
NAME_ROLE,
DESCRIPTION_ROLE,
ICON_ROLE,
PROGRESS_ROLE,
SOURCE_ROLE,
DETAILS_ROLE,
LOG_ROLE,
) = [Qt.UserRole + i for i, _ in enumerate(keys)]
class Device(Item):
@item_property(role=NAME_ROLE)
def name(self):
return ""
@item_property(role=DESCRIPTION_ROLE)
def description(self):
return ""
@item_property(role=ICON_ROLE)
def icon(self):
return ""
@item_property(role=PROGRESS_ROLE)
def progress(self):
return 0
@item_property(role=SOURCE_ROLE)
def source(self):
return ""
@item_property(role=DETAILS_ROLE)
def details(self):
return dict()
@item_property(role=LOG_ROLE)
def log(self):
return list()
class DeviceManager(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._model = QStandardItemModel()
self._model.setItemRoleNames(dict(zip(ROLES, keys)))
def get_model(self):
return self._model
model = Property(QObject, fget=get_model, constant=True)
def add_device(self, *, name, description, icon, progress, source, details, log):
dev = Device()
dev.name = name
dev.description = description
dev.icon = icon
dev.progress = progress
dev.source = source
dev.details = details
dev.log = log
self.model.appendRow(dev)
return dev
def main():
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
manager = DeviceManager()
engine.rootContext().setContextProperty("device_manager", manager)
url = QUrl("main.qml")
def handle_object_created(obj, obj_url):
if obj is None and url == obj_url:
QCoreApplication.exit(-1)
engine.objectCreated.connect(handle_object_created, Qt.QueuedConnection)
engine.load(url)
processor = manager.add_device(
name="Processor",
description="Intel i7 6600k",
icon="/resources/images/chip.svg",
progress=10,
source="resources/qml/Processor.qml",
details={
"badge": "Intel® Core i5 processor",
"cache": "6144 KB",
"clock": "4200000",
},
log=[
"Starting Cpu Test",
"Detected Intel CPU",
"Performing intense calculations",
"Processing calculations still",
"Cleaning up",
"Test Passed",
],
)
memory = manager.add_device(
name="Memory",
description="Kingston 16GB DDR3",
icon="/resources/images/ram.svg",
progress=50,
source="resources/qml/Memory.qml",
details={
"device_locator_string": "ChannelB-DIMM1",
"device_set": 0,
"error_handle": 65534,
"extended_size": 0,
"form_factor": "Unknown",
},
log=[
"Starting Memory Test",
"Detected 2 x RAM modules",
"Performing intense calculations",
"Processing calculations still",
"Cleaning up",
"Test Failed",
],
)
def update_progress(value):
processor.progress = value
animation = QVariantAnimation(
startValue=processor.progress, endValue=100, duration=3 * 1000
)
animation.valueChanged.connect(update_progress)
animation.start()
ret = app.exec_()
sys.exit(ret)
if __name__ == "__main__":
main()
main.qml主要.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
id: root
visible: true
width: 400
height: 400
ListView {
id: view
property url currentSource: ""
model: device_manager.model
width: parent.width / 2
height: parent.height
spacing: 10
clip: true
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
currentIndex: -1
ScrollBar.vertical: ScrollBar {
}
highlight: Rectangle {
color: "lightsteelblue"
radius: 5
}
delegate: Rectangle {
id: rect
color: "transparent"
border.color: ListView.isCurrentItem ? "red" : "green"
height: column.height
width: ListView.view.width
Column {
id: column
Text {
text: model.name
}
ProgressBar {
from: 0
to: 100
value: model.progress
}
Label {
text: "Log:"
font.bold: true
font.pointSize: 15
}
Text {
text: model.log.join("\n")
}
}
MouseArea {
anchors.fill: parent
onClicked: {
rect.ListView.view.currentIndex = index;
rect.ListView.view.currentSource = model.source;
}
}
}
}
Rectangle {
x: view.width
width: parent.width / 2
height: parent.height
color: "salmon"
Loader {
anchors.centerIn: parent
source: view.currentSource
}
}
}
Processor.qml处理器.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
Rectangle{
color: "red"
width: 100
height: 40
Text{
text: "Processor"
anchors.centerIn: parent
}
}
Memory.qml Memory.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
Rectangle{
color: "blue"
width: 100
height: 40
Text{
text: "Memory"
anchors.centerIn: parent
}
}
├── main.py
├── main.qml
└── resources
└── qml
├── Memory.qml
└── Processor.qml
I want to create a Qt data model with a structure like below to use in Python and QML.我想创建一个具有如下结构的 Qt 数据 model 用于 Python 和 ZC477ABFB2FD4959A20ZD5.E0 If any values or keys are changed, added, or deleted in Python or QML I would need the values to be updated on the other side (QML or Python).
如果在 Python 或 QML 中更改、添加或删除任何值或键,我需要在另一侧(QML 或 Python)更新这些值。 This would ideally be the model used in a ListView and I would only display certain fields for the ListView.
理想情况下,这将是 ListView 中使用的 model,我只会显示 ListView 的某些字段。 But I would use this data model to store all my information.
但我会使用这些数据 model 来存储我的所有信息。 When a test is performed for memory in Python I would want to write that test log information to this data model and display that in QML.
当对 Python 中的 memory 执行测试时,我想将该测试日志信息写入此数据 model 并在 ZC4DZ7AB02FD4444444D4DZ7AB02FD4 中显示I have read about QAbstractListModel, but I am unsure if I can make nested objects or lists and whether they would update automatically or not.
我已经阅读了 QAbstractListModel,但我不确定我是否可以制作嵌套对象或列表以及它们是否会自动更新。
System: {
Processor: {
name: 'Processor',
description: 'Intel i7 6600k',
iconSource: '/resources/images/chip.svg',
progressValue: 100,
pageSource: '/resources/qml/Processor.qml',
details: {
"badge": "Intel® Core i5 processor",
"cache": "6144 KB",
"clock": "4200000"
}
testLog: [
'Starting Cpu Test',
'Detected Intel CPU',
'Performing intense calculations',
'Processing calculations still',
'Cleaning up',
'Test Passed'
]
}
Memory: {
name: 'Memory',
description: 'Kingston 16GB DDR3',
iconSource: '/resources/images/ram.svg',
progressValue: 50,
pageSource: '/resources/qml/Processor.qml',
details: {
"device_locator_string": "ChannelB-DIMM1",
"device_set": 0,
"error_handle": 65534,
"extended_size": 0,
"form_factor": "Unknown"
},
testLog: [
'Starting Memory Test',
'Detected 2 x RAM modules',
'Performing intense calculations',
'Processing calculations still',
'Cleaning up',
'Test Failed'
]
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.