在Qt中,控件与控件之间的联系全靠信号(Signals)与槽(Slots)来进行对接。例如一个清空按钮发送了点击的信号,输入框通过连接该按钮的点击信号,当收到点击信号时,进行清空输入框文本的操作,如此完成清空输入框内容的逻辑。
一、信号和槽的关系
用一张图来说明信号与槽的关系:
比方说有一个看不见东西可怜的小明,他需要买肉做红烧肉,当他来到集市上,听到有猪肉荣的叫卖声时,就去买肉回家做红烧肉了。
- 小明即是接收信号的槽,当他收到卖肉的信号,他就会买肉然后做红烧肉
- 卖肉的猪肉荣,他的叫卖声就是在发信号
如果小明想要买肉做红烧肉,同时他又想修仙,那么当他听到卖肉的叫卖声和卖仙丹的叫卖声,他就会到两个摊位上都买,然后可能用肉做红烧肉,仙丹直接吃;也有可能把肉和仙丹一起做成仙丹炒肉的名菜再吃。
所以一个槽函数可以接收多种信号,一个信号也可以发送给多个槽(相当于小明哥哥、小明妹妹、小明弟弟、包租婆、包租公、火云邪神等等都来买肉)。
二、Qt Designer中添加自定义槽
比如说你有个自定义的槽函数test在主控件中,则只需要右键该主控件(根控件),选择改变 信号/槽即可:
第一步
第二步
第三步
在代码中添加槽函数,并在槽函数中实现相应逻辑:
class MyWindow(QMainWindow):
...
def test(self):
# 实现逻辑
pass
自定义信号也是如此操作。 关于槽函数中的参数,可以根据信号的传参类型填写。
三、代码中添加自定义信号
首先,添加自定义信号的基类需要为QObject,否则将会报错:
3.1 代码展示
# -*- coding: utf-8 -*-
from PySide6 import QtCore
class CustomWidget(QtCore.QObject):
sig_test_1 = QtCore.Signal()
sig_test_2 = QtCore.Signal(float)
sig_test_3 = QtCore.Signal(tuple)
sig_test_4 = QtCore.Signal(int, int)
def test_1(self):
self.sig_test_1.emit()
def test_2(self):
self.sig_test_2.emit(0.5)
def test_3(self):
self.sig_test_3.emit(('test', 20, [2, 3, 4, 5]))
def test_4(self):
self.sig_test_4.emit(20, 30)
- 自定义信号Signal发送时参数不定,如果需要发送多个参数,个人比较推荐直接用tuple,这样就可以直接在槽函数中通过语法糖获取参数,例:name, age, score_list = data
- 自定义信号的发送信号时机需要开发者自己确认,相当灵活
3.2 自定义信号什么时候使用
一般来说,在开发Qt项目时,很多控件可能无法我们的满足,因此需要继承控件去扩展功能,此时经常会使用到自定义信号来完成功能。
四、代码中信号与槽的连接
def test(index):
pass
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
# currentIndexChanged为ComboBox的一个自带信号,会发送一个下标
self.unit_combo_box.currentIndexChanged.connect(self.unit_change)
self.unit_combo_box.currentIndexChanged.connect(test)
def unit_change(self, index):
pass
可以看到一个信号连接槽函数通过connect方法,可以是对象方法,也可以是一个单独的函数。
对应的,还有一个disconnect方法来解除连接,不过用到的情况不多。
五、 如何查看控件内置信号与槽
点进控件的源码中,查看该部分内容:
如果类似pyqtgraph的库,信号也可以在类名下方找到:
六、总结
为了连接各个控件,完成需求开发,信号与槽的应用不可避免,如何运用好内置信号与槽,如何定义好自定义信号和槽都是需要慢慢开发,积累经验的。