使用 Python 初始化和自定义 QML 组件

问题描述

有没有办法让我将 QML 组件视为对象,并在 Python 中对其进行初始化?例如,这是一个简化的盒子 QML: 我希望能够复制构造函数方法可以在 Java 中执行的操作。我希望能够通过 Python 脚本自定义每个框上的文本,同时创建多个相互独立的框实例。

import QtQuick 2.0
import QtQuick.Controls 2.0

Item {
    id: BoxItem
    width: 800
    height: 118

    Rectangle {

        id: BoxRect
        height: 118
        color: "#55f555"
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.top: parent.top

        Text {
            id: textItem
            width: 463
            height: 43
            color: "#000000"
            text: qsTr("Header Text")
            anchors.left: parent.left
            anchors.top: parent.top
            font.pixelSize: 38
            verticalAlignment: Text.AlignVCenter
            font.family: "Roboto"
            textformat: Text.AutoText
            anchors.leftMargin: 20
            anchors.topMargin: 20
        }
    }

}

这是我当前从 Qt 模板版本修改的 Python 脚本:

import os
import sys
from pathlib import Path

import PySide6.QtQml
from PySide6.QtQuick import qquickview
from PySide6.QtCore import Qt,QUrl
from PySide6.QtGui import QGuiApplication


if __name__ == '__main__':

    #Set up the application window
    app = QGuiApplication(sys.argv)
    view = qquickview()
    view.setResizeMode(qquickview.SizeRootObjectToView)

    #Load the QML file
    qml_file = Path(__file__).parent / "Main.qml"
    view.setSource(QUrl.fromLocalFile(os.fspath(qml_file.resolve())))

    #Show the window
    if view.status() == qquickview.Error:
        sys.exit(-1)
    view.show()

    #execute and cleanup
    app.exec()
    del view

快速说明:我正在使用自定义构建的 QML 组件,而不是尝试编辑由 QT 制作的预先存在的组件。

解决方法

应用另一种技术(编程语言、库、框架)的概念通常是使用其他技术的一种糟糕方法。每种技术都有自己的方法和良好做法来实现任何要求。

在 QML 的情况下,其他语言如 C++、python 等通常被认为是实现业务逻辑(类似后端的东西),而 QML 负责视图和操作。在这种情况下,建议创建一个 QObject,该 QObject 提供其他创建、修改等数据的 QObject,这可以在视图中反映出来。在这种特殊情况下,对于需求,使用模型和自定义 qml 项就足够了。

Box.qml

import QtQuick 2.0
import QtQuick.Controls 2.0

Item {
    id: boxItem
    width: 800
    height: 118

    property alias text: textItem.text

    Rectangle {

        id: boxRect
        height: 118
        color: "#55f555"
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.top: parent.top

        Text {
            id: textItem
            width: 463
            height: 43
            color: "#000000"
            anchors.left: parent.left
            anchors.top: parent.top
            font.pixelSize: 38
            verticalAlignment: Text.AlignVCenter
            font.family: "Roboto"
            textFormat: Text.AutoText
            anchors.leftMargin: 20
            anchors.topMargin: 20
        }
    }
}

ma​​in.qml

import QtQuick 2.0
import QtQuick.Controls 2.0

Item {
    id: root
    ScrollView 
    {
        anchors.fill: parent
        Column{
            Repeater{
                model: manager.model
                Box{
                    text: model.display
                }
            }
        }
    }
}

ma​​in.py

import os
import sys
from pathlib import Path


from PySide6.QtCore import Property,QObject,Qt,QUrl
from PySide6.QtGui import QGuiApplication,QStandardItemModel,QStandardItem
from PySide6.QtQuick import QQuickView


class Manager(QObject):
    def __init__(self,parent=None):
        super().__init__(parent)
        self._model = QStandardItemModel()

    @Property(QObject,constant=True)
    def model(self):
        return self._model


if __name__ == "__main__":

    # Set up the application window
    app = QGuiApplication(sys.argv)
    view = QQuickView()
    view.setResizeMode(QQuickView.SizeRootObjectToView)

    manager = Manager()
    view.rootContext().setContextProperty("manager",manager)

    qml_file = Path(__file__).parent / "main.qml"
    view.setSource(QUrl.fromLocalFile(os.fspath(qml_file.resolve())))

    if view.status() == QQuickView.Error:
        sys.exit(-1)
    view.resize(640,480)
    view.show()

    for i in range(20):
        item = QStandardItem(f"item-{i}")
        manager.model.appendRow(item)

    app.exec()