关于 QML 和 PySide2 的几个问题
问题描述
我有以下情况,想用几个Qml:welcome.qml"、create.qml"、dashboard.qml"
I have the following cases, I want to use several Qml: "welcome.qml", "create.qml", "dashboard.qml"
在哪些情况下使用QQuickview或QqmlApplicationEngine?
in which cases to use QQuickview or QqmlApplicationEngine.?
我正在使用QQmlAplicatiobEngine"并使用 findChild 在对象中搜索以获取信号并处理逻辑,如果信号完成条件,我使用 engine.load 加载另一个 QML.
I am using "QQmlAplicatiobEngine" and search in the object with findChild to get the signal, and handle the logic, If the signal completes a condition, I use the engine.load to load another QML.
蟒蛇:
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"
}
}
}
create.qml:
create.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 效果更好.
It's better with QQuickview or QQmlAplicationEngine.
解决方案
从OP提供的内容,我会指出以下几个方面:
From what the OP provides, I will point out the following aspects:
什么时候应该使用
QQmlAplicationEngine
或QQuickview
?QQmlAplicationEngine
还是QQuickview
更好?
When should
QQmlAplicationEngine
orQQuickview
be used? is betterQQmlAplicationEngine
orQQuickview
?
使用一个或另一个取决于 QML 的根元素,如果根是 Window 或 ApplicationWindow,则必须使用 QQmlAplicationEngine,如果它是 Item 或其派生类,则可以使用 QQuickView.因此,对于上述一个并不比另一个更好.如果我用根窗口加载 QML 或用 QQuickView 加载 ApplicationWindow 会发生什么?然后它将显示 2 个窗口:一个来自 QQuickView,另一个来自 Window 或 ApplicationWindow.如果我用 QQmlApplicationEngine 加载带有 Item 的 QML 怎么办?好吧,您需要将它放在一个 Window 中,如 文档:
The use of one or the other depends on the root element of the QML, if the root is Window or ApplicationWindow then you must use QQmlAplicationEngine, if instead it is an Item or its derivatives you can use QQuickView. So for the above one is not better than another. What happens if I load a QML with root Window or ApplicationWindow with QQuickView? Then it will show 2 windows: One will be from the QQuickView and the other from the Window or ApplicationWindow. What if I load a QML with Item with QQmlApplicationEngine? Well you will need to place it inside a Window as indicated by the docs:
与 QQuickView 不同,QQmlApplicationEngine 不会自动创建根窗口.如果您使用 Qt Quick 中的可视项目,则需要将它们放置在 Window 内.
Unlike QQuickView, QQmlApplicationEngine does not automatically create a root window. If you are using visual items from Qt Quick, you will need to place them inside of a Window.
不要从 python/C++ 访问 QML 元素
QML 对变量有自己的处理方式,因此您可以随时删除或创建它,没有任何确定的内容,因此访问这些对象可能很危险,因为它们可能没有分配内存.正确的做法是反其道而行之,将 QObject 导出到 QML 并在 QML 中建立连接.
QML has its own handling of the variables so you could delete it or create it at any time, there is nothing determined, so accessing these objects can be dangerous since they may not have allocated memory. The right thing is to do the opposite, export a QObject to QML and make connections in QML.
我们会将上述概念应用到 OP 提供的代码中(有些类型我已经更正了).
We will apply the above concepts to the code provided by the OP (there are types that I have corrected).
首先,既然根是ApplicationWindow,那么就应该使用QQmlApplicationEngine.
First of all, since the roots are ApplicationWindow, then QQmlApplicationEngine should be used.
您可以使用 setContextProperty 将后端导出到 QML,然后直接调用插槽,而不是在每个元素中创建更改"信号.使用 rootObjects() 获取对象是危险的,因为有异步加载的 qmls,而是使用 objectCreated 信号.
Instead of creating the "change" signal in each element, you can export the backend to QML using setContextProperty and then call the slots directly. To obtain the object using rootObjects() is dangerous since there are qmls that are loaded asynchronously, instead use the objectCreated signal.
main.py
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_())
welcome.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"
}
}
}
wallet.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()
}
}
}
相关文章