PyQt5学习日记(二):信号与槽

一、基本介绍

       信号和槽是一种高级接口,应用于对象之间的通信,它是 QT 的核心特性,也是 QT 区别于其它工具包的重要地方。它为高层次的事件处理自动生成所需要的附加代码。在我们所熟知的很多 GUI 工具包中,窗口小部件 (widget) 都有一个回调函数用于响应它们能触发的每个动作,这个回调函数通常是一个指向某个函数的指针。但是,在 QT 中信号和槽取代了这些凌乱的函数指针,使得我们编写这些通信程序更为简洁明了。

       所有从 QObject 或其子类 ( 例如 Qwidget) 派生的类都能够包含信号和槽。当对象改变其状态时,信号就由该对象发射 (emit) 出去,这就是对象所要做的全部事情,它不知道另一端是谁在接收这个信号。这就是真正的信息封装,它确保对象被当作一个真正的软件组件来使用。槽用于接收信号,但它们是普通的对象成员函数。一个槽并不知道是否有任何信号与自己相连接。而且,对象并不了解具体的通信机制。

       你可以将很多信号与单个的槽进行连接,也可以将单个的信号与很多的槽进行连接,甚至于将一个信号与另外一个信号相连接也是可能的,这时无论第一个信号什么时候发射系统都将立刻发射第二个信号。总之,信号与槽构造了一个强大的部件编程机制。


二、信号与槽

2.1 信号

       当对象的状态发生改变的时候,信号就由该对象发射 (emit) 出去。当一个信号被发射(emit)时候,与其关联的槽函数被立刻执行。其中该对象只负责发送信号,发射该信号的对象并不知道是那个对象在接收这个信号。这样保证了对象与对象之间的低耦合。
如果存在信号和多个槽函数相关联的时候,当信号被发射时,这些槽的执行顺序将会是随机的、不确定的。

2.2 槽

       用于接受信号,而且槽只是普通的对象成员函数。当和槽连接的信号被发射时,槽会被调用。一个槽并不知道是否有任何信号与自己相连接。

2.3 信号与槽的绑定

       通过调用 QObject 对象的 connect 函数来将某个对象的信号与另外一个对象的槽函数相关联,这样当发射者发射信号时,接收者的槽函数将被调用。该函数的定义如下:

connect(slot[, type=PyQt5.QtCore.Qt.AutoConnection[, no_receiver_check=False]])
Parameters:
slot – the slot to connect to, either a Python callable or another bound signal.
type – the type of the connection to make.
no_receiver_check – suppress the check that the underlying C++ receiver instance still exists and deliver the signal anyway.

       当信号与槽没有必要继续保持关联时,我们可以使用 disconnect 函数来断开连接。其定义如下:

disconnect([slot])
Parameters: slot – the optional slot to disconnect from, either a Python callable or another bound signal. If it is omitted then all slots connected to the signal are disconnected.


三、信号与槽的特点

1、一个信号可以连接到多个槽;
当信号发出后,槽函数都会被调用,但是调用的顺序是随机的,不确定的。

self.slider.valueChanged.connect(self.pBar.setValue) self.slider.valueChanged.connect(self.lcdNumber.display)

QSlider数据的变化同时绑定在setValue()和display()两个槽上。

2、多个信号可以连接到同一个槽;
其中任何一个信号发出,槽函数都会被执行。

self.buttonOn.clicked.connect(self.showMessage)
self.buttonOff.clicked.connect(self.showMessage)

showMessage()同时绑定在两个button的clicked信号上。

3、信号的参数可以是任何的Python类型;

如list,dict等python独有的类型。自定义信号的时候举例说明。

4、信号和槽的连接可以被移除;

比如断开某个特定信号的关联。

self.buttonOn.clicked.disconnect(self.showMessage)

5、信号可以和另外一个信号进行关联;
第一个信号发出后,第二个信号也同时发送。

比如关闭系统的信号发出之后,同时会发出保存数据的信号。


四、实例

说实话对于像我这样的新手来说看着就脑壳疼,想学会它没办法,我们还是简化一下概念吧:

所有QObject类都可以使用信号槽,换句话来说继承自PyQt5中的类基本上都可以使用信号槽机制。当然非QObject也是可以通过其他一些办法来使用信号槽的。

仅仅有了信号和槽是不行的,我们还需要了解:
       信号(Signal)、槽(slot)、连接(connect)、动作事件(action)、发射(emit)、发送者、接受者等等一些列的知识。好吧,别搞的那么复杂行不行,我们还是学学该怎么用吧。

在Qt Designer中为我们提供了一些基本的信号槽方法,我们来看看:
       点击工具栏上的“编辑信号/槽”,进入信号槽编辑模式,我们可以直接在发送者(button)上按住鼠标左键不放,拖动到接收者(Form窗体)上。这样就建立起了连接。

接着,会弹出配置连接对话框。

左边是发送者(按钮)的信号(动作事件),右边是接收者(窗体)的槽(动作事件)。

如图所示,我信号选择的是clicked,槽选择的是close:

我们看一下编译后生成的代码:

self.quitButton.clicked.connect(Form.close)

实现的功能是:当按钮点击之后关闭窗体。

流程:
按钮是信号发送者,当点击按钮之后会发送一个信号出去,通过这段代码程序内部的通讯机制知道这个按钮的点击事情被连接到窗体的关闭事件上去了,然后通知接受者窗体,你该运行槽函数close了!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from PyQt5 import QtWidgets  
from untitled import Ui_Form  
"""点击按钮,在控制台输出helloworld"""  
class mywindow(QtWidgets.QWidget,Ui_Form):  
    def __init__(self):  
        super(mywindow,self).__init__()  
        self.setupUi(self)
        self.myButton.clicked.connect(self.myPrint)   #槽函数不用加括号
    def myPrint(self):                              #定义槽
        print("helloWorld")
  
if __name__=="__main__":  
    import sys  
  
    app=QtWidgets.QApplication(sys.argv)  
    myshow=mywindow()  
    myshow.show()  
    sys.exit(app.exec_())  

五、小提示

槽其实就个函数(方法),Qt5中的槽函数不在限定必须是slot,可以是普通的函数、类的普通成员函数、lambda函数等。编译期间就会检查信号与槽是否存在!

信号的connect连接最好放在init析构函数里面,这样只会声明一次连接,如果在类方法(函数中)使用的话,要记得disconnect,否则connect会连接多次,导致程序异常。

信号槽函数不用加 (),否则可能会导致连接异常。


参考链接1:https://blog.csdn.net/zhulove86/article/details/52530214
参考链接2:https://blog.csdn.net/a359680405/article/details/45148717