首页 > 解决方案 > 关于 QML 和 PySide2 的几个问题

问题描述

我有以下情况,我想使用几个Qml:“welcome.qml”、“create.qml”、“dashboard.qml”

在哪些情况下使用 QQuickview 或 QqmlApplicationEngine。?

我正在使用“QQmlAplicatiobEngine”并使用 findChild 在对象中搜索以获取信号并处理逻辑,如果信号完成一个条件,我使用 engine.load 加载另一个 QML。

Python:

class guiBackend(QObject):

    def __init__(self):
        self.engine = QQmlApplicationEngine()
        self.context = self.engine.rootContext()
        self.context.setContextProperty("main", self.engine)
        self.welcome()

    def welcome(self):
        self.engine.load("welcome.qml")
        self.engine.rootObjects()[0].show()
        ob = self.engine.rootObjects()[0]
        next = ob.findChild(QObject, "timer")
        print(dir(next))
        if  path.exists('data.some'):
            next.change.connect(self.open_account)
        else:
            next.change.connect(self.create_account)
    def create(self):
        self.engine.rootObjects()[0].close()
        self.engine.load("create.qml")
        self.engine.rootObjects()[1].show()
        add = ob.findChild(QObject, "addWallet")
        recovery = ob.findChild(QObject, "recovery")
        add.change.connect(self.add_account)
        recovery.change.connect(self.recovery)
        #self.open_account load dashboard.qml and self.account load form.qml

if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    gui = guiBackend()
    sys.exit(app.exec_())

Qml:

ApplicationWindow {
    id: welcome
    width: 650; height: 390
    opacity: 1
    visible: true
    minimumHeight: 232
    minimumWidth:226
    title: "open account"
    flags: Qt.SplashScreen
    Item {

        id: element
        x: 9
        y: 88
        width: 560
        height: 300
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
        Timer {
        signal change
        objectName: "timer"
        interval: 5000; running: true; repeat: false
        onTriggered: change()
        }
        Image {
            id: image
            x: 130
            y: 60
            width: 342
            height: 188
            anchors.verticalCenterOffset: -56
            anchors.horizontalCenterOffset: 0
            anchors.verticalCenter: parent.verticalCenter
            anchors.horizontalCenter: parent.horizontalCenter
            source: "neirons_logo.png"
            fillMode: Image.PreserveAspectFit
        }

        AnimatedImage {
            id: animatedImage
            x: 236
            y: 200
            width: 100
            height: 100
            source: "loading.gif"
        }
    }
}

创建.qml:

ApplicationWindow {
    id: create
    width: 210; height: 210

    Rectangle {
        id: rectangle
        x: 70
        y: 132
        width: 200
        height: 200
        color: "#72ded8"
        anchors.verticalCenterOffset: 0
        anchors.horizontalCenterOffset: 0
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter

        ColumnLayout {
            x: 60
            y: 73
            width: 109
            height: 128
            anchors.verticalCenter: parent.verticalCenter
            anchors.horizontalCenter: parent.horizontalCenter

            TextInput {
                id: nameAccount
                objectName: textAccount
                text: qsTr("nameAccount")
                Layout.fillWidth: true
                Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
                Layout.preferredHeight: 20
                Layout.preferredWidth: 80
                verticalAlignment: Text.AlignVCenter
                font.pixelSize: 12
            }

            TextInput {
                id: nameAccount
                objectName: textAccount
                text: qsTr("Name Account")
                Layout.fillWidth: true
                Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
                Layout.preferredHeight: 20
                Layout.preferredWidth: 80
                font.pixelSize: 12
            }
        }

        Button {
            signal addinfo
            id: submitNameAccount
            objectName: submit
            x: 50
            y: 134
            width: 81
            height: 23
            text: qsTr("Add")
            font.bold: true
            font.pointSize: 12
            anchors.horizontalCenter: parent.horizontalCenter
            onClicked: addinfo()
    }


}

最好使用 QQuickview 或 QQmlAplicationEngine。

标签: pythonqmlpyside2

解决方案


从OP提供的内容来看,我会指出以下几个方面:

  • 什么时候应该使用QQmlAplicationEngineQQuickview使用?更好QQmlAplicationEngine还是QQuickview

    一个或另一个的使用取决于 QML 的根元素,如果根是 Window 或 ApplicationWindow,那么您必须使用 QQmlAplicationEngine,如果它是 Item 或其派生类,您可以使用 QQuickView。因此,对于上述一个并不比另一个更好。如果我用根窗口加载 QML 或用 QQuickView 加载 ApplicationWindow 会发生什么?然后它将显示 2 个窗口:一个来自 QQuickView,另一个来自 Window 或 ApplicationWindow。如果我用 QQmlApplicationEngine 加载带有 Item 的 QML 怎么办?好吧,您需要将其放置在 Window 中,如文档所示:

    与 QQuickView 不同,QQmlApplicationEngine 不会自动创建根窗口。如果您使用 Qt Quick 中的可视项目,则需要将它们放置在 Window 内。

  • 不要从 python/C++ 访问 QML 元素

    QML 对变量有自己的处理,因此您可以随时删除或创建它,没有任何确定的内容,因此访问这些对象可能很危险,因为它们可能没有分配内存。正确的做法是相反,将 QObject 导出到 QML 并在 QML 中建立连接。


我们将上述概念应用到 OP 提供的代码中(有些类型我已经更正了)。

  • 首先,既然根是ApplicationWindow,那么就应该使用QQmlApplicationEngine。

  • 您可以使用 setContextProperty 将后端导出到 QML,然后直接调用插槽,而不是在每个元素中创建“更改”信号。使用 rootObjects() 获取对象是危险的,因为有异步加载的 qmls,而是使用 objectCreated 信号。

主文件

import os

from PyQt5 import QtCore, QtGui, QtQml

CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))


class Backend(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)

        self._engine = QtQml.QQmlApplicationEngine()
        self._welcome = None
        self._wallet = None
        self.engine.objectCreated.connect(self.on_object_created)
        self.engine.rootContext().setContextProperty("backend", self)

        self.load_welcome()

    @property
    def engine(self):
        return self._engine

    @property
    def welcome(self):
        return self._welcome

    @property
    def wallet(self):
        return self._wallet

    @staticmethod
    def create_url(qml):
        return QtCore.QUrl.fromLocalFile(os.path.join(CURRENT_DIR, qml))

    def load_welcome(self):
        self.engine.load(self.create_url("welcome.qml"))

    @QtCore.pyqtSlot(QtCore.QObject, QtCore.QUrl)
    def on_object_created(self, obj, url):
        if url == self.create_url("welcome.qml"):
            self._welcome = obj
        elif url == self.create_url("wallet.qml"):
            self._wallet = obj

    @QtCore.pyqtSlot()
    def create_wallet(self):
        self.welcome.close()
        self.engine.load(self.create_url("wallet.qml"))

    @QtCore.pyqtSlot()
    def add_info(self):
        print("add_info")


if __name__ == "__main__":
    import sys

    app = QtGui.QGuiApplication(sys.argv)
    backend = Backend()

    sys.exit(app.exec_())

欢迎.qml

import QtQuick 2.14
import QtQuick.Controls 2.14

ApplicationWindow {
    id: root
    width: 650; height: 390
    opacity: 1
    visible: true
    minimumHeight: 232
    minimumWidth:226
    title: "open account"
    flags: Qt.SplashScreen
    Item {
        id: element
        x: 9
        y: 88
        width: 560
        height: 300
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
        Timer {
            interval: 5000; running: true; repeat: false
            onTriggered: backend.create_wallet()
        }
        Image {
            id: image
            x: 130
            y: 60
            width: 342
            height: 188
            anchors.verticalCenterOffset: -56
            anchors.horizontalCenterOffset: 0
            anchors.verticalCenter: parent.verticalCenter
            anchors.horizontalCenter: parent.horizontalCenter
            source: "neirons_logo.png"
            fillMode: Image.PreserveAspectFit
        }

        AnimatedImage {
            id: animatedImage
            x: 236
            y: 200
            width: 100
            height: 100
            source: "loading.gif"
        }
    }
}

钱包.qml

import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14


ApplicationWindow {
    id: root
    visible: true
    width: 210; height: 210

    Rectangle {
        id: rectangle
        x: 70
        y: 132
        width: 200
        height: 200
        color: "#72ded8"
        anchors.verticalCenterOffset: 0
        anchors.horizontalCenterOffset: 0
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter

        ColumnLayout {
            x: 60
            y: 73
            width: 109
            height: 128
            anchors.verticalCenter: parent.verticalCenter
            anchors.horizontalCenter: parent.horizontalCenter

            TextInput {
                id: nameAccount1
                text: qsTr("nameAccount")
                Layout.fillWidth: true
                Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
                Layout.preferredHeight: 20
                Layout.preferredWidth: 80
                verticalAlignment: Text.AlignVCenter
                font.pixelSize: 12
            }

            TextInput {
                id: nameAccount2
                text: qsTr("Name Account")
                Layout.fillWidth: true
                Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
                Layout.preferredHeight: 20
                Layout.preferredWidth: 80
                font.pixelSize: 12
            }
        }

        Button {
            id: submitNameAccount
            x: 50
            y: 134
            width: 81
            height: 23
            text: qsTr("Add")
            font.bold: true
            font.pointSize: 12
            anchors.horizontalCenter: parent.horizontalCenter
            onClicked: backend.add_info()
        }
    }
}

推荐阅读