PySide6 + QML - 信号与槽02 - QML Button向 Python 传递参数
·
导言

这张图描述了 QML 前端 和 Python 后端 的交互关系,用于说明 信号 (signal) 和 槽 (slot) 的连接方式。实际上是展示了一个 QML → Python 单向调用流程。
两个 QML 按钮组件,每个按钮都有一个 clicked 信号。
- 按钮1 触发clicked信号,发送字符串"button1 clicked"给Python的backed.print_button1()
- 按钮2 触发clicked信号,发送字符串"button2 clicked"给Python的backed.print_button2()
效果如下所示:
工程代码:
- github: https://github.com/q164129345/myPyside6_QML/tree/main/basic03_button_slot_with_para
- gitee: https://gitee.com/wallace89/myPyside6_QML/tree/main/basic03_button_slot_with_para
一、main.py
import sys
from PySide6.QtCore import QObject, Slot
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
class Backend(QObject):
@Slot(str)
def print_button1(self, name):
print(f"{name}")
@Slot(str)
def print_button2(self, name):
print(f"{name}")
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):
@Slot(str)
def print_button1(self, name):
print(f"{name}")
@Slot(str)
def print_button2(self, name):
print(f"{name}")
- 继承
QObject:让这个类能够作为 Qt 的对象被 QML 识别和调用。 @Slot(str):- 告诉 Qt 这是一个槽函数,QML 可以直接调用它。
- (str) 指定参数类型为字符串。这样 QML 在调用时必须传入字符串。
二、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("Hello PySide6 + QML") // 窗口标题,qsTr用于国际化
// Row布局:水平排列子元素
Row {
anchors.centerIn: parent // 将Row布局锚定到父元素(窗口)的中心
spacing: 20 // 子元素之间的间距为20像素
// 第一个按钮
Button {
id: btn1 // 给按钮设置唯一标识符,便于引用
text: "button1" // 按钮显示的文本
onClicked: { // 点击事件处理器
// 调用Python后端的方法,传递参数
backend.print_button1("button1 clicked")
// 修改按钮文本为"clicked"
btn1.text = "clicked"
}
}
// 第二个按钮
Button {
id: btn2 // 给按钮设置唯一标识符
text: "button2" // 按钮显示的文本
onClicked: { // 点击事件处理器
// 调用Python后端的方法,传递参数
backend.print_button2("button2 clicked")
// 修改按钮文本为"clicked"
btn2.text = "clicked"
}
}
}
}
关键点说明
Row {
anchors.centerIn: parent // 将Row布局锚定到父元素(窗口)的中心
spacing: 20 // 子元素之间的间距为20像素
// 第一个按钮
Button {
id: btn1 // 给按钮设置唯一标识符,便于引用
text: "button1" // 按钮显示的文本
onClicked: { // 点击事件处理器
// 调用Python后端的方法,传递参数
backend.print_button1("button1 clicked")
// 修改按钮文本为"clicked"
btn1.text = "clicked"
}
}
// 第二个按钮
Button {
id: btn2 // 给按钮设置唯一标识符
text: "button2" // 按钮显示的文本
onClicked: { // 点击事件处理器
// 调用Python后端的方法,传递参数
backend.print_button2("button2 clicked")
// 修改按钮文本为"clicked"
btn2.text = "clicked"
}
}
}
- Row:水平布局容器,两个按钮并排。
- Button 1:显示文字 “button1”。点击时调用 backend.print_button1(“button1 clicked”) → Python 输出。
- Button 2:同理,调用 backend.print_button2(“button2 clicked”)。
三、细节补充
3.1、@Slot()可以传递哪些类型的变量?
| Python 类型声明 | 对应 QML 类型 | 示例 |
|---|---|---|
| int | int | @Slot(int) |
| float | real | @Slot(float) |
| bool | bool | @Slot(bool) |
| str | string | @Slot(str) |
| list | var (数组) | @Slot(list) |
| dict | var (对象) | @Slot(dict) |
| QObject | Item/对象引用 | @Slot(QObject) |
| 示例代码 |
- 接收整数
@Slot(int)
def set_number(self, n):
print(f"number={n}")
QML 调用:
onClicked: backend.set_number(42)
- 接收浮点数
@Slot(float)
def set_ratio(self, r):
print(f"ratio={r}")
QML 调用:
onClicked: backend.set_ratio(3.14)
- 接收布尔值
@Slot(bool)
def toggle(self, state):
print("ON" if state else "OFF")
QML 调用:
onClicked: backend.toggle(true)
- 接收数组 / 字典
@Slot(list)
def print_list(self, arr):
print(arr)
@Slot(dict)
def print_dict(self, obj):
print(obj)
QML 调用:
onClicked: backend.print_list([1,2,3])
onClicked: backend.print_dict({"name":"Alice", "age":18})
- 指定返回值
@Slot(int, int, result=int)
def add(self, a, b):
return a + b
QML 调用:
onClicked: console.log( backend.add(5, 7) )
总结
- 参数:支持 int, float, bool, str, list, dict, QObject 等。
- 返回值:用 result=类型 声明。
- QML 中:int/real/bool/string/var 对应 Python 的基本类型。
3.2、@Slot()装饰器的必要性
场景分析
class Backend(QObject):
# 情况1: 没有 @Slot()
# Qt 内部:找到 Python 对象 -> 查找方法 -> 类型转换 -> 调用
# 每次调用都要做类型推断
def print_button1(self, name):
print(f"{name}")
# 情况2: 有 @Slot()
# Qt 内部:已知参数类型 -> 直接调用
# 性能提升 20-50%
@Slot(str)
def print_button1(self, name):
print(f"{name}")
- 情况1与情况2都能正常工作。但是,情况2的性能提升20~50%。
官方建议
来自Qt for Python文档:
Best Practice: Always use @Slot() decorator for methods that will be:
- Called from QML
- Connected to signals
- Exposed to Qt’s meta-object system
While it may work without @Slot(), using it ensures: - Better performance
- Type safety
- Proper integration with Qt’s meta-object system
总的来说,宁可多加 @Slot(),也不要少加!这是零成本的性能和安全提升。
更多推荐


所有评论(0)