信号与槽是 Qt 中的一种事件处理机制,用于实现对象之间的通信;例如,按钮被点击,产生一个"被点击"的信号,然后执行某个事先连接的槽函数;
基本概念
- 信号(Signal):事件发生的通知(如"按钮被点了"、"窗口大小被调整了")
- 槽(Slot):响应信号的函数(如"退出程序"、"保存文件")
- 连接(Connect):把信号和槽配对起来
连接信号与槽

连接信号与槽函数的示例代码如下:
import sys
from PySide6.QtCore import Slot
from PySide6.QtWidgets import (
QApplication, QWidget, QTextEdit, QPushButton, QVBoxLayout, QHBoxLayout
)
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("信号与槽示例")
# 创建控件
self.input = QTextEdit()
self.btn_clear = QPushButton("清空")
self.btn_add = QPushButton("添加内容")
self.btn_exit = QPushButton("退出")
# 布局设置
layout = QVBoxLayout()
layout.addWidget(self.input)
btn_layout = QHBoxLayout()
btn_layout.addWidget(self.btn_clear)
btn_layout.addWidget(self.btn_add)
btn_layout.addWidget(self.btn_exit)
layout.addLayout(btn_layout)
self.setLayout(layout)
# 连接信号和槽
self.btn_clear.clicked.connect(self.input.clear)
self.btn_add.clicked.connect(self.add_text)
self.btn_exit.clicked.connect(QApplication.quit)
@Slot()
def add_text(self):
self.input.append("hello wrold!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec())
这个示例中,按钮btn_clear
用于清空输入框中的内容,按钮btn_add
用于向输入框中追加内容,按钮btn_exit
用于退出程序;
第 32 ~ 34 行中,用于连接按钮的信号与槽函数;其中clicked
是按钮预定义(内置)的信号,表示按钮被点击,connect()
用于连接信号与槽函数,self.input.clear()
是输入框预定义的槽函数,self.add_text()
为自定义的槽函数,自定义槽函数可使用装饰器@Slot()
使其更安全;
如果不加 @Slot 会怎样?
PySide6 会把它当作普通 Python 函数,依然能被连接;
但加了 @Slot 可以:
- 提升性能
- 增加类型安全
- 避免内存泄漏
connect() 函数
在此信号和接收器之间建立连接;
connect(receiver[, type=Qt.AutoConnection])
- receiver:可调用类型,可以是槽函数或信号;
- type:信号与槽之间可使用的连接类型;它决定了特定信号是立即传送到槽,还是排队等待稍后传送;
连接类型 | 描述 |
---|---|
Qt.AutoConnection | 默认,如果接收者位于发出信号的线程中,使用Qt.DirectConnection ;否则使用Qt.QueuedConnection ; |
Qt.DirectConnection | 信号发出时,槽函数会立即被调用;槽函数在信号线程中执行。 |
Qt.QueuedConnection | 当控制权返回到接收者线程的事件循环时,调用槽函数;槽函数在接收者的线程中执行。 |
Qt.BlockingQueuedConnection | 与Qt.QueuedConnection 类似,但信号线程会阻塞,直到槽函数返回为止;如果接收方位于信号线程中,则不得使用此连接,否则应用程序将死锁。 |
断开连接
及时断开不再需要的连接,防止内存泄漏;
#断开与clicked信号连接的指定槽
button.clicked.disconnect(function)
#断开与clicked信号连接的所有槽
button.clicked.disconnect()
一个信号连接多个槽
一个信号可以与多个槽函数进行连接;
槽函数也可被多个信号同时连接;
def log():
print("[LOG] clicked.")
button.clicked.connect(log)
button.clicked.connect(lambda: print("Do something!"))
带参数的信号
某些内置信号携带参数,这对于在组件之间传递信息非常有用。
例如QLineEdit
控件,内容改变时textChanged(str)
信号携带一个参数,槽函数接收参数的方法如下:
# TODO
# 输入框
self.input = QLineEdit(self)
self.label = QLabel("当前输入内容:", self)
# 信号连接槽函数
self.input.textChanged.connect(self.on_text_changed)
#self.input.textChanged.connect(self.label.setText)
@Slot(str)
def on_text_changed(self, text: str):
# 槽函数:将当前输入的文本显示在标签上
self.label.setText(f"当前输入内容:{text}")
自定义信号
PySide6 可使用Signal
类来定义一个信号,示例如下:
from PySide6.QtCore import QObject, Signal, Slot
class A(QObject):
message = Signal(str)
class B(QObject):
@Slot(str)
def print_message(self, msg):
print("Received:", msg)
a = A()
b = B()
a.message.connect(b.print_message)
a.message.emit("Hello!")
代码中,message
就是自定义带参数的信号,通过connect
连接到槽函数print_message
,并通过emit
方法发送信号;
自定义多个参数的信号:
message = Signal(str,int)
...
@Slot(str,int)
def print_message(self, msg, value):
print("Received:",msg,value)
...
a.message.emit("hello",123)
使用 @Slot 重载签名
你可以为同一个函数使用多个@Slot
重载签名:
class Receiver(QObject):
@Slot(str)
@Slot(int)
def handle(self, value):
print("收到:", value)
这表示handle
可以接收str
类型或int
类型的参数,Qt 会根据信号的参数类型自动匹配合适的重载版本。