PySide6 + QML - 信号与槽04 - Python 主动发射信号驱动 QML UI
·
导言
在前面的示例中,交互主要由 QML 调用 Python 函数完成,Python 端处于被动响应。本篇将演示如何由 Python 主动发射信号并驱动 QML UI 更新,实现从“被动调用”到“主动推送”的双向交互。
这张图描述了 Python 端通过信号(Signal)把字符串传递给 QML。QML 接收到信号后,更新界面上的标签文字,从而实现 Python 主动驱动 QML UI。
效果如下所示:
工程代码:
- github: https://github.com/q164129345/myPyside6_QML/tree/main/basic05_signal
- gitee: https://gitee.com/wallace89/myPyside6_QML/tree/main/basic05_signal
一、main.py
# python3.10.11 - PySide6==6.9
import sys
from PySide6.QtCore import QObject, Slot, Signal, QTimer
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
class Backend(QObject):
# 定义信号
messageChanged = Signal(str)
def __init__(self):
super().__init__() # 初始化父类
self.counter = 0
# 创建QTimer定时器,每秒触发一次(不要使用python自带的定时器,会卡UI)
self.timer = QTimer(self)
self.timer.timeout.connect(self.updateMessage)
self.timer.start(1000) # 1000毫秒
def updateMessage(self):
# 每1秒发送一次信号
self.counter += 1
self.messageChanged.emit(f"Hello from Python! {self.counter}") # 发送信号
if __name__ == "__main__":
# 创建应用程序和引擎
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
# qml与python交互
backend = Backend() # 实例化python后端对象
engine.rootContext().setContextProperty("backend", backend) # 注册到QML环境(名叫 “backend”)
# 加载QML文件
engine.addImportPath(sys.path[0]) # 当前项目路径
engine.loadFromModule("Example", "Main") # 模块(Example) + QML文件名(Main.qml)
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec())
关键点说明
class Backend(QObject):
# 定义信号
messageChanged = Signal(str)
def __init__(self):
super().__init__() # 初始化父类
self.counter = 0
# 创建QTimer定时器,每秒触发一次
self.timer = QTimer(self)
self.timer.timeout.connect(self.updateMessage)
self.timer.start(1000) # 1000毫秒
def updateMessage(self):
# 每1秒发送一次信号
self.counter += 1
self.messageChanged.emit(f"Hello from Python! {self.counter}") # 发送信号
messageChanged = Signal(str):创建一个信号,名为messageChanged,传递消息的类型是字符串。super().__init__():因为显式重写了__init__()构造函数,记得调用super().__init__()初始化父类QObject。另外,如果没有重写__init__()的话,Python会自动帮我们调用super().__init__()。所以,之前的例子都不需要调用super().__init__()。self.messageChanged.emit():是将字符串“信号“发送给QML。emit()方法用于触发/发送之前定义的messageChanged信号,这是Qt信号-槽机制中的"发送端"。
二、Main.qml
// 导入QML基础模块,包含基本的QML元素
import QtQuick 2.15
// 导入Qt控件模块,包含Button等界面控件
import QtQuick.Controls 2.15
// 应用程序主窗口
ApplicationWindow {
visible: true // 窗口可见
width: 400 // 窗口宽度为400像素
height: 300 // 窗口高度为300像素
title: qsTr("Python主动更新 -> QML显示") // 窗口标题,qsTr用于国际化
Label {
id: label
anchors.centerIn: parent // 标签居中显示
text: "等待Python消息..." // 标签初始文本内容
}
// 绑定Python信号
Connections {
target: backend // 连接到名为backend的Python对象
function onMessageChanged(msg) {
label.text = msg // 更新标签文本为传递的新文本
}
}
}
关键点说明
// 绑定Python信号
Connections {
target: backend // 连接到名为backend的Python对象
function onMessageChanged(msg) {
label.text = msg // 更新标签文本为传递的新文本
}
}
Connections:是QML中的一个特殊元素,用于建立信号-槽连接,它允许QML对象监听其他对象的信号。target:指定要监听的对象(比如Backend对象)。function onMessageChanged(msg):onMessageChanged是信号处理器的命名约定(不能随意更改),当Python端的messageChanged信号发出时,这个函数会自动被调用。
为什么不能用其他名字?
这是Qt/QML框架的约定规则,具体原因:
- 自动连接机制:QML引擎会自动识别以on开头且后面跟着信号名的函数,并将其作为该信号的处理器
- 命名转换规则:
- Python信号:messageChanged
- QML处理函数:onMessageChanged
- 规则:on + 信号名(首字母大写)
- 框架内部实现:Qt的元对象系统依赖这种命名约定来建立信号和槽之间的连接
这就像是一个"合约",Python端发出messageChanged信号,QML端必须用onMessageChanged来接收,这样Qt框架才知道它们是对应的。
更多推荐

所有评论(0)