How to access QML\QtQuick controls from PySide?
我正在尝试从启动QQmlApplication引擎的python文件访问FileDialog控件,以便检索文件路径属性。我已经在.qml文件中设置了信号,但是无法通过python文件中的id访问文件对话框来设置插槽。 application.py中的findChild方法返回None。这是代码:
application.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import sys from PySide2.QtGui import QGuiApplication from PySide2.QtQml import QQmlApplicationEngine, QQmlFileSelector sys_argv = sys.argv sys_argv += ['--style', 'material'] app = QGuiApplication(sys_argv) window = QQmlApplicationEngine() window.load("QML/main.qml") fileDialog = window.findChild(QQmlFileSelector,"fileDialog") print(fileDialog) app.exec_() |
Page1.qml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Dialogs 1.2 Page { width: 600 height: 400 header: Label { text: qsTr("Prepare Data") horizontalAlignment: Text.AlignHCenter font.pixelSize: Qt.application.font.pixelSize * 2 padding: 10 } Button { text: qsTr("Load data") anchors.centerIn: parent onClicked: fileDialog.visible = true padding: 10 } signal folderSelected() FileDialog { id: fileDialog selectFolder: true title: qsTr("Select the data directory") folder: shortcuts.home onAccepted: { parent.folderSelected() } } } |
main.qml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import QtQuick 2.0 import QtQuick.Controls 2.12 import QtQuick.Controls.Material 2.12 ApplicationWindow{ visible: true title: qsTr("Main window") width: 1000 height: 800 Material.theme: Material.Light Material.accent: Material.Orange SwipeView { id: swipeView anchors.fill: parent Page1 { } Page2 { } Page3 { } } } |
在"将引用推送到QML"部分中的一个旧答案中,解释了如何从QML更新某些python对象,该方法是Qt建议的方法,并且是现在应使用的方法。使用当前方法,您需要建立一个在许多情况下可能有问题的对象名。
因此解决方案是创建一个导出到QML的QObject并更新qproperty,这将发出一个信号,该信号连接到我们可以执行所需逻辑的插槽。另一方面,FileDialog返回一个URL,因此该属性必须为QUrl:
main.qml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import os import sys from PySide2 import QtCore, QtGui, QtQml class FileManager(QtCore.QObject): file_url_Changed = QtCore.Signal(QtCore.QUrl) def __init__(self, parent=None): super(FileManager, self).__init__(parent) self._file_url = QtCore.QUrl() def get_file_url(self): return self._file_url def set_file_url(self, file_url): if self._file_url != file_url: self._file_url = file_url self.file_url_Changed.emit(self._file_url) file_url = QtCore.Property(QtCore.QUrl, fget=get_file_url, fset=set_file_url, notify=file_url_Changed) @QtCore.Slot(QtCore.QUrl) def on_file_url_changed(file_url): print(file_url.toLocalFile()) if __name__ == '__main__': sys.argv += ['--style', 'material'] app = QtGui.QGuiApplication(sys.argv) file_manager = FileManager() file_manager.file_url_Changed.connect(on_file_url_changed) engine = QtQml.QQmlApplicationEngine() engine.rootContext().setContextProperty("file_manager", file_manager) file = os.path.join(os.path.dirname(os.path.realpath(__file__)),"QML","main.qml") engine.load(QtCore.QUrl.fromLocalFile(file)) if not engine.rootObjects(): sys.exit(-1) sys.exit(app.exec_()) |
Page1.qml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Dialogs 1.2 Page { width: 600 height: 400 header: Label { text: qsTr("Prepare Data") horizontalAlignment: Text.AlignHCenter font.pixelSize: Qt.application.font.pixelSize * 2 padding: 10 } Button { text: qsTr("Load data") anchors.centerIn: parent onClicked: fileDialog.visible = true padding: 10 } FileDialog { id: fileDialog selectFolder: true title: qsTr("Select the data directory") folder: shortcuts.home onAccepted: { file_manager.file_url = fileDialog.fileUrl // <--- } } } |