关于 QML 和 PySide2 的几个问题
Posted
技术标签:
【中文标题】关于 QML 和 PySide2 的几个问题【英文标题】:several questions about QML and PySide2 【发布时间】:2020-02-25 13:21:56 【问题描述】:我有以下情况,想用几个Qml:“welcome.qml”、“create.qml”、“dashboard.qml”
在哪些情况下使用QQuickview或QqmlApplicationEngine?
我正在使用“QQmlAplicatiobEngine”并使用 findChild 在对象中搜索以获取信号并处理逻辑,如果信号完成条件,我使用 engine.load 加载另一个 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:
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 效果更好。
【问题讨论】:
提供minimal reproducible example。如果没有 QML 代码,除了了解您的逻辑之外,很难为您提供任何解决方案。另一方面,避免使用 findChild:这是一种不好的做法,带来的问题多于解决方案。 我应该使用什么来正确加载 qmls 并使用良好的做法 显示dashboard.qml和form.qml,同时显示open_account和create_account方法 代码很多,但了解如何通过良好实践从 welcome.qml 更改为 create.qml,我会了解如何编写其余代码 只显示“create.qml”的顶部,你不能显示一个极简的实现示例吗? 【参考方案1】:从OP提供的内容,我会指出以下几个方面:
什么时候应该使用QQmlAplicationEngine
或QQuickview
? QQmlAplicationEngine
或 QQuickview
更好?
使用一个或另一个取决于 QML 的根元素,如果根是 Window 或 ApplicationWindow,则必须使用 QQmlAplicationEngine,如果它是 Item 或其派生类,则可以使用 QQuickView。因此,对于上述一个并不比另一个好。如果我使用根窗口加载 QML 或使用 QQuickView 加载 ApplicationWindow 会发生什么?然后它将显示 2 个窗口:一个来自 QQuickView,另一个来自 Window 或 ApplicationWindow。如果我使用 QQmlApplicationEngine 加载带有 Item 的 QML 怎么办?好吧,您需要将其放置在 the docs 所示的 Window 中:
与 QQuickView 不同,QQmlApplicationEngine 不会自动创建根窗口。如果您使用 Qt Quick 中的可视项目,则需要将它们放置在 Window 中。
不要从 python/C++ 访问 QML 元素
QML 对变量有自己的处理方式,因此您可以随时删除或创建它,没有任何确定的内容,因此访问这些对象可能很危险,因为它们可能没有分配内存。正确的做法是反其道而行之,将 QObject 导出到 QML 并在 QML 中建立连接。
我们会将上述概念应用到 OP 提供的代码中(有些类型我已经更正了)。
首先,既然根是ApplicationWindow,那么就应该使用QQmlApplicationEngine。
您可以使用 setContextProperty 将后端导出到 QML,然后直接调用插槽,而不是在每个元素中创建“更改”信号。使用 rootObjects() 获取对象是危险的,因为有异步加载的 qmls,而是使用 objectCreated 信号。
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()
【讨论】:
我刚刚发现了一个星光层,你写的东西扩展了我的思维,我可以更好地理解 PYQT 的功能以上是关于关于 QML 和 PySide2 的几个问题的主要内容,如果未能解决你的问题,请参考以下文章
使用 PySide2 将 python 信号连接到 QML ui 插槽
PySide2 QML - 如何在另一个 QML 文件中引用 QML 文件作为组件?
PySide2 + QML:QApplication:通过了无效的样式覆盖,忽略它