QML 的 PySide6 后端是否有更简洁的方法?

Is there a cleaner way for backend in PySide6 for QML?

您好,我正在使用 Model class 为列表和组合框提供项目。问题是我每次都对每个元素使用 setContextProperty() 函数。我正在寻找一种解决方案,其中所有元素(列表和组合框)都使用相同的 ContextProperty。此外,我猜 JSON 文件可以动态加载,而不是一开始就加载所有文件。

main.py

class Model(QAbstractListModel, QObject):
    """ it reads JSON file, that is given as argument,
    and creates the model"""

if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    model1 = Model("file1.json")
    model2 = Model("file2.json")
    model3 = Model("file3.json")
    model4 = Model("file4.json")
    model5 = Model("file5.json")

    engine.rootContext().setContextProperty("model1", model1)
    engine.rootContext().setContextProperty("model2", model2)
    engine.rootContext().setContextProperty("model3", model3)
    engine.rootContext().setContextProperty("model4", model4)
    engine.rootContext().setContextProperty("model5", model5)

    engine.rootContext().setContextProperty("applicationDirPath", os.path.dirname(__file__))
    engine.load(os.path.join(os.path.dirname(__file__), "main.qml"))

    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec())

您可以创建一个将所有模型公开为 属性 列表的 QObject,然后使用 Repeater 动态创建组合框。

以下为演示:

import os
import sys
from pathlib import Path

from PySide6.QtCore import Property, QCoreApplication, QObject, Qt, QUrl, Signal
from PySide6.QtGui import QGuiApplication, QStandardItem, QStandardItemModel
from PySide6.QtQml import QQmlApplicationEngine

CURRENT_DIRECTORY = Path(__file__).resolve().parent


class Model(QStandardItemModel):
    def __init__(self, values, parent=None):
        super().__init__(parent)
        for value in values:
            item = QStandardItem(value)
            self.appendRow(item)


class Manager(QObject):
    models_changed = Signal(name="modelsChanged")

    def __init__(self, parent=None):
        super().__init__(parent)
        self._models = []

    @Property("QVariantList", notify=models_changed)
    def models(self):
        return self._models

    def append_model(self, model):
        self._models.append(model)
        self.models_changed.emit()


def main():
    app = QGuiApplication(sys.argv)

    manager = Manager(app)

    manager.append_model(Model(["item11", "item12", "item13"]))
    manager.append_model(Model(["item21", "item22", "item23"]))
    manager.append_model(Model(["item31", "item32", "item33"]))
    manager.append_model(Model(["item41", "item42", "item43"]))

    engine = QQmlApplicationEngine()

    context = engine.rootContext()
    context.setContextProperty("applicationDirPath", os.fspath(CURRENT_DIRECTORY))
    context.setContextProperty("managerModel", manager)

    filename = os.fspath(CURRENT_DIRECTORY / "main.qml")
    url = QUrl.fromLocalFile(filename)

    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)

    sys.exit(app.exec())


if __name__ == "__main__":
    main()
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

ApplicationWindow {
    width: 640
    height: 480
    visible: true

    ColumnLayout {
        anchors.centerIn: parent

        Repeater {
            id: repeater

            model: managerModel.models

            ComboBox {
                model: modelData
                textRole: "display"
                Layout.fillWidth: true
            }

        }

    }

}

旁注:QAbstractListModel 是一个 QObject,因此双重继承是无用的,因此您应该将其更改为:class Model(QAbstractListModel):