将属性注入 QML 组件

Injecting Properties into QML-Component

我是 Qt/PyQt 的新手,目前正在努力使用一些基本功能。我想做的是,从 python 动态加载 QML-Views (*.qml) 文件并即时替换特定内容。例如,一个复选框被选中,我当前视图的一部分被另一个 qml 文件替换。首先我想通过 PyQt 提供这个逻辑,但似乎 StackView 是一个更好的主意 (multiple qml files in pyqt)。

但是,在这种情况下,我无法将属性注入到我的 QML 文件中。我只能将 属性 注入 rootContext。然而,这限制了我的 QML-Views 的使用,因为我一次只能使用一个视图(相同类型)。我想将属性动态注入 QML-Views 并使它们仅对该特定视图可见。在这种情况下,我可以在后端使用多个对象多次使用相同的视图来捕获信号。

这是我的 SimpleMainWindow.qml 文件(主视图:

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.3
import QtQuick.Controls 1.4

ApplicationWindow {
    id: window
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    objectName : "WINDOW"
    property ApplicationWindow appWindow : window

}

这里是我尝试加载的文件 (TestViewButton.qml):

import QtQuick 2.9
import QtQuick.Controls 1.4

Button {
    id: test
    text: "test"
    objectName : "Button"
    onClicked: {
        configurator.sum(1, 2)
        configurator.info("TestOutput")
    }
}

Python 文件加载 QML-View(组件)

from PyQt5.QtCore import QObject, QUrl
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine, QQmlComponent

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

    engine.load("qml/SimpleMainWindow.qml")
    engine.quit.connect(app.quit)

    rootWindow = engine.rootObjects()[0].children()[0].parent()

    # create component
    component = QQmlComponent(engine)
    component.loadUrl(QUrl("qml/TestViewButton.qml"))

    configurator = SignalHandler()
    component.setProperty("configurator", configurator)

    itm = component.create()
    itm.setParentItem(rootWindow.children()[0])

    itm.setProperty("configurator", configurator)

    app.exec_()

以及我用来处理来自视图 (SignalHandler.py) 的信号的 python 对象:

from PyQt5.QtCore import QObject, pyqtSlot

class SignalHandler(QObject):

    @pyqtSlot(int, int)
    def sum(self, arg1, arg2):
        print("Adding two numbers")

    @pyqtSlot(str)
    def info(self, arg1):
        print("STR " + arg1)

按钮加载正常(顺便说一句,有没有更好的方法来识别我想添加我的按钮的父级,没有用 findChild 查看)。 component.setProperty..... 部分不起作用。如果我在引擎的 rootContext 中设置 属性 它工作正常(调用 SignalHandler 方法)。已经检查过类似的主题(例如 ...)

这可能吗,还是我这里有问题?

谢谢

据我了解,您只想在 TestViewButton.qml 中加载配置对象,而在 SimpleMainWindow.qml 中不可见。

要做到这一点 TestViewButton.qml 在加载时必须有自己的 QQmlContext 而不是 rootContext().

为了测试我的反应并观察这种行为,我们将创建一个类似的按钮,尝试使用 configurator,如果按下它,它应该抛出一个错误,指出 属性 不存在但是如果加载的按钮被 QQmlComponent 按下应该可以正常工作。

qml/SimpleMainWindow.qml

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.3
import QtQuick.Controls 1.4

ApplicationWindow {
    id: window
    visible: true
    width: 640
    color: "red"
    height: 480
    title: qsTr("Hello World")

    Button {
        x: 100
        y: 100
        text: "ApplicationWindow"
        onClicked: {
            console.log("ApplicationWindow")
            configurator.sum(1, 2)
            configurator.info("TestOutput")
        }
    }
}

正如我之前评论的那样,我添加了具有新上下文的组件:

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

    configurator = SignalHandler()

    engine.load("qml/SimpleMainWindow.qml")
    engine.quit.connect(app.quit)

    rootWindow = engine.rootObjects()[0]
    content_item = rootWindow.property("contentItem")

    context = QQmlContext(engine)
    component = QQmlComponent(engine)
    component.loadUrl(QUrl("qml/TestViewButton.qml"))
    itm = component.create(context)
    context.setContextProperty("configurator", configurator)
    itm.setProperty("parent", content_item)

    sys.exit(app.exec_())

最后我们得到以下输出:

qml: Component
Adding two numbers
STR TestOutput
qml: ApplicationWindow
file:///xxx/qml/SimpleMainWindow.qml:20: ReferenceError: configurator is not defined
qml: Component
Adding two numbers
STR TestOutput
qml: ApplicationWindow
file:///xxx/qml/SimpleMainWindow.qml:20: ReferenceError: configurator is not defined

我们在哪里观察到期望的行为。完整的例子可以在下面的link.

中找到