如何从嵌套的QML页面向python发出信号



在我的QML/python应用程序中,我可以从main.QML向python代码发出信号。但现在在main.qml中,我添加了StackLayout来加载另一个page1.qml。在page1.qml是按钮,现在我想从这个按钮向python发出信号。

我使用这个方法将信号从main.qml文件发送到python:但不知道如何从嵌套的page1.qml中发出它

主.py

from PySide2.QtCore import QObject, QUrl, Slot, Signal, Qt
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
class Foo(QObject):
@Slot(str)
def test_slot(self, input_string : str):
print(input_string)
if __name__ == "__main__":
import os
import sys
app = QGuiApplication()
foo = Foo()
engine = QQmlApplicationEngine()

#CHANGES: line excluded engine.rootContext().setContextProperty("foo", foo)

qml_file = "main.qml"
current_dir = os.path.dirname(os.path.realpath(__file__))
filename = os.path.join(current_dir, qml_file)
engine.load(QUrl.fromLocalFile(filename))
if not engine.rootObjects():
sys.exit(-1)

#CHANGES: connect QML signal to Python slot
engine.rootObjects()[0].test_signal.connect(foo.test_slot, type=Qt.ConnectionType.QueuedConnection)

sys.exit(app.exec_())

main.qml

import QtQuick 2.13
import QtQuick.Controls 2.13
ApplicationWindow {
visible: true

//CHANGES: declare signal
signal test_signal(string input_string)
Button {
anchors.centerIn: parent
text: "Example"
//CHANGES: emit signal
onClicked: test_signal("Test string")
}
}

https://stackoverflow.com/a/69595659/5166312

非常感谢。

  1. 为嵌套页面添加objectName字符串属性(如果它们在单独的文件中,则包括这种情况(:
    objectName: "page1_objname"
    
  2. 从Python(或C++(后端访问嵌套页面
    qmlpage1 = engine.rootObjects()[0].findChild(QObject, "page1_objname")
    
  3. 像在Python或C++后端一样连接插槽和信号(您的问题或我的答案中已经有代码了https://stackoverflow.com/a/69595659/5166312)。
    qmlpage1.page1_signal.connect(
    test_object.test_slot3,
    type=Qt.ConnectionType.QueuedConnection)
    

我在上的测试示例中使用StackLayout、两个嵌套页面、3个信号和3个插槽的整个项目https://github.com/Ornstein89/pyside6-qml-slotsignal.

main.py

# This Python file uses the following encoding: utf-8
import sys
from pathlib import Path
from PySide6.QtCore import QObject, QUrl, Slot, Signal, Qt
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
class TestClass(QObject):
'''
Object - slot-owner and signal-acceptor
'''
@Slot(str)
def test_slot1(self, input_string : str):
print(input_string)
@Slot(str)
def test_slot2(self, input_string : str):
print(input_string)
@Slot(str)
def test_slot3(self, input_string : str):
print(input_string)
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
test_object = TestClass()
qml_file = Path(__file__).resolve().parent / "main.qml"
engine.load(qml_file)
if not engine.rootObjects():
sys.exit(-1)
# !!! connect ApplicationWindow.mainapp_signal() to test_object.test_slot1
engine.rootObjects()[0]
.mainapp_signal.connect(
test_object.test_slot1,
type=Qt.ConnectionType.QueuedConnection)
# !!! access nested page1 from python backend
qmlpage1 = engine.rootObjects()[0].findChild(QObject, "page1_objname")
# !!! and connect MyPage1.page1_signal() to test_object.test_slot2
qmlpage1.page1_signal.connect(
test_object.test_slot2,
type=Qt.ConnectionType.QueuedConnection)
# !!! access nested page2 from python backend
qmlpage2 = engine.rootObjects()[0].findChild(QObject, "page2_objname")
# !!! and connect MyPage2.page2_signal() to test_object.test_slot3
qmlpage2.page2_signal.connect(
test_object.test_slot3,
type=Qt.ConnectionType.QueuedConnection)
sys.exit(app.exec())

main.qml

import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
ApplicationWindow {
width: 480
height: 640
visible: true
title: qsTr("Example for Stackoverflow")
// !!! singal №1 in root QML Object - most easy to connect in main.py
signal mainapp_signal(string input_string)
StackLayout {
id : stacklayout
anchors.fill: parent
MyPage1 {
id: page1
}
MyPage2 {
id: page2
}
}
}

MyPage1.qml

import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
Page{
id: page1
// !!! singal №2 in nested QML Object
signal page1_signal(string input_string)
// !!! important - this name is used
// to access page1 from C++ or Python backend
objectName: "page1_objname"
Button{
text: "Go to page 2"
anchors.centerIn: parent
onClicked: {
stacklayout.currentIndex = 1
// call root object signal from nested object
mainapp_signal("mainapp_signal() from page1");
// call nested object signal from same object
page1_signal("page1_signal() from page1");
// call another nested object signal
page2.page2_signal("page2_signal() from page1");
}
}
}

MyPage2.qml

import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
Page{
id: page2
// !!! singal №3 in nested QML Object
signal page2_signal(string input_string)
// !!! important - this name is used
// to access page2 from C++ or Python backend
objectName: "page2_objname"
Button{
text: "Go to page 1"
anchors.centerIn: parent
onClicked: {
stacklayout.currentIndex = 0
}
}
}

您可以添加一个Conections元素来使用加载组件的信号
请查看此处的文档。

此外,您还可以为page1.qml项声明一个组件,并使用LoadersourceComponent属性。通过这种方式,您可以使用组件内部的信号来调用外部方法。请查看此处的文档。

最新更新