信号和槽机制是 QT 的核心机制,要精通 QT 编程就必须对信号和槽有所了解。信号和槽是一种高级接口,应用于对象之间的通信,它是 QT 的核心特性,也是 QT 区别于其它工具包的重要地方。
信号和槽是用来在对象间传递数据的方法:当一个特定事件发生的时候,信号会被发射出来,槽调用是用来响应相应的信号的。Qt中对象已经包含了许多预定义的信号(基本组件都有各自特有的预定义的信号),根据使用的场景也可以添加新的信号。同样Qt的对象中已经包含了许多预定义的槽函数,但也可以根据使用的场景添加新的槽函数。
一、概念简介
所有继承qwidget的控件都支持信号与槽机制。
信号:当一个信号发生改变时,向外界发出的信息。
当一个信号被发射的时候,与其关联的槽函数被立刻执行。其中该对象只负责发送信号,发射该信号的对象并不知道是那个对象在接收这个信号。这样保证了对象与对象之间的低耦合。
如果存在信号和多个槽函数相关联的时候,当信号被发射时,这些槽的执行顺序将会是随机的、不确定的。
槽:一个执行某些操作的函数或者方法。
当和槽连接的信号被发射时,槽会被调用。一个槽并不知道是否有任何信号与自己相连接。
信号与槽机制:主要分两种
手动操作:信号连接槽
自动操作:当信号发出时,连续的槽函数会自动执行
信号连接
通过调用 QObject 对象的 connect 函数来将某个对象的信号与另外一个对象的槽函数相关联,这样当发射者发射信号时,接收者的槽函数将被调用。该函数的定义如下:
1
|
object .信号.connet(槽函数) |
当信号与槽没有必要继续保持关联时,可以使用 disconnect 函数来断开连接。其定义如下:
1
|
disconnect(槽函数) |
信号和槽的特点:
1.一个信号可以连接到多个槽:当信号发出后,槽函数都会被调用,但是调用的顺序是随机的,不确定的。
2.多个信号可以连接到同一个槽:其中任何一个信号发出,槽函数都会被执行。
3.信号的参数可以是任何的Python类型,如list,dict等python独有的类型。自定义信号的时候举例说明。
4.信号和槽的连接可以被移除:比如断开某个特定信号的关联。
5.信号可以和另外一个信号进行关联:第一个信号发出后,第二个信号也同时发送。比如关闭系统的信号发出之后,同时会发出保存数据的信号。
二、代码样例
整体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
import sys from PyQt5.QtCore import Qt from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,QGridLayout,QLabel,QHBoxLayout, QGroupBox, QVBoxLayout, QApplication,QProgressBar,QPushButton,QMessageBox) class SignalSlot(QWidget): def __init__( self ): super (SignalSlot, self ).__init__() self .initUI() def initUI( self ): self .controlsGroup = QGroupBox( "运行样本" ) self .lcdNumber = QLCDNumber( self ) self .slider = QSlider(Qt.Horizontal, self ) self .pBar = QProgressBar( self ) vbox = QVBoxLayout() vbox.addWidget( self .pBar) vbox.addWidget( self .lcdNumber) vbox.addWidget( self .slider) self .controlsGroup.setLayout(vbox) controlsLayout = QGridLayout() self .label1 = QLabel( "保存状态:" ) self .saveLabel = QLabel() self .label2 = QLabel( "运行状态:" ) self .runLabel = QLabel() self .buttonSave = QPushButton( "保存" ) self .buttonRun = QPushButton( "运行" ) self .buttonStop = QPushButton( "停止" ) self .buttonDisconnect = QPushButton( "解除关联" ) self .buttonConnect = QPushButton( "绑定关联" ) controlsLayout.addWidget( self .label1, 0 , 0 ) controlsLayout.addWidget( self .saveLabel, 0 , 1 ) controlsLayout.addWidget( self .label2, 1 , 0 ) controlsLayout.addWidget( self .runLabel, 1 , 1 ) controlsLayout.addWidget( self .buttonSave, 2 , 0 ) controlsLayout.addWidget( self .buttonRun, 2 , 1 ) controlsLayout.addWidget( self .buttonStop, 2 , 2 ) controlsLayout.addWidget( self .buttonDisconnect, 3 , 0 ) controlsLayout.addWidget( self .buttonConnect, 3 , 1 ) layout = QHBoxLayout() layout.addWidget( self .controlsGroup) layout.addLayout(controlsLayout) self .setLayout(layout) self .buttonRun.clicked.connect( self .buttonSave.clicked) self .slider.valueChanged.connect( self .pBar.setValue) self .slider.valueChanged.connect( self .lcdNumber.display) self .buttonSave.clicked.connect( self .showMessage) self .buttonRun.clicked.connect( self .showMessage) self .buttonDisconnect.clicked.connect( self .unbindConnection) self .buttonConnect.clicked.connect( self .bindConnection) self .buttonStop.clicked.connect( self .stop) self .setGeometry( 300 , 500 , 500 , 180 ) self .setWindowTitle( '信号和槽' ) def showMessage( self ): if self .sender().text() = = "保存" : self .saveLabel.setText( "Saved" ) elif self .sender().text() = = "运行" : self .runLabel.setText( "Running" ) def unbindConnection( self ): self .slider.valueChanged.disconnect() def bindConnection( self ): def stop( self ): self .saveLabel.setText("") self .runLabel.setText("") if __name__ = = '__main__' : app = QApplication(sys.argv) ex = SignalSlot() ex.show() sys.exit(app.exec_()) |
控件说明:
控件类型 | 控件名称 | 作用 |
---|---|---|
controlsGroup | QGroupBox | 为构建分组框提供了支持。分组框通常带有一个边框和一个标题栏,作为容器部件来使用,在其中可以布置各种窗口部件。 |
lcdNumber | QLCDNumber | 用于显示一个带有类似液晶显示屏效果的数字。 |
slider | QSlider | 提供一个垂直或者水平的滑动条,滑动条是一个用于控制有界值典型的控件,它允许用户沿水平或者垂直方向在某一范围内移动滑块,并将滑块所在的位置转换为一个合法范围内的整数值 |
pBar | QProgressBar | 提供了一个水平或垂直的进度条 |
label1 | QLabel |
|
buttonSave | QPushButton | 常用的按钮控件 |
界面说明:
程序样本运行的界面逻辑,先设定运行的程序样本数量,然后先保存后运行的逻辑状态。通过slider的滑动来改变progressBar和LCD的显示数据;“保存”按钮保存运行的样本;“运行”按钮运行程序样本;“解除关联”解除slider.valueChanged信号的绑定,此时slider的滑动,不会改变progressBar和LCD的显示。
1
2
3
4
5
6
7
8
9
|
self .controlsGroup = QGroupBox( "运行样本" ) self .lcdNumber = QLCDNumber( self ) self .slider = QSlider(Qt.Horizontal, self ) self .pBar = QProgressBar( self ) vbox = QVBoxLayout() vbox.addWidget( self .pBar) vbox.addWidget( self .lcdNumber) vbox.addWidget( self .slider) self .controlsGroup.setLayout(vbox) |
实例化一个QGroupBox,在其中添加QProgressBar、QLCDNumber、QSlider控件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
controlsLayout = QGridLayout() self .label1 = QLabel( "保存状态:" ) self .saveLabel = QLabel() self .label2 = QLabel( "运行状态:" ) self .runLabel = QLabel() self .buttonSave = QPushButton( "保存" ) self .buttonRun = QPushButton( "运行" ) self .buttonStop = QPushButton( "停止" ) self .buttonDisconnect = QPushButton( "解除关联" ) self .buttonConnect = QPushButton( "绑定关联" ) controlsLayout.addWidget( self .label1, 0 , 0 ) controlsLayout.addWidget( self .saveLabel, 0 , 1 ) controlsLayout.addWidget( self .label2, 1 , 0 ) controlsLayout.addWidget( self .runLabel, 1 , 1 ) controlsLayout.addWidget( self .buttonSave, 2 , 0 ) controlsLayout.addWidget( self .buttonRun, 2 , 1 ) controlsLayout.addWidget( self .buttonStop, 2 , 2 ) controlsLayout.addWidget( self .buttonDisconnect, 3 , 0 ) controlsLayout.addWidget( self .buttonConnect, 3 , 1 ) |
通过QGridLayout()添加标签以及按钮。
1
2
3
4
|
layout = QHBoxLayout() layout.addWidget( self .controlsGroup) layout.addLayout(controlsLayout) self .setLayout(layout) |
最后通过QHBoxLayout将左右两个界面合并,形成最终界面。
信号与槽说明:
signal和slot进行绑定。
1.一个信号绑定多个槽:
1
2
|
self .slider.valueChanged.connect( self .pBar.setValue) self .slider.valueChanged.connect( self .lcdNumber.display) |
slider控件的valueChanged信号,同时与QProgressBar的setValue(),QLCDNumber的display()槽函数绑定,当valueChanged信号触发的时候,这两个槽函数均会被调用。
2.多个信号绑定到一个槽:
1
2
|
self .buttonSave.clicked.connect( self .showMessage) self .buttonRun.clicked.connect( self .showMessage) |
buttonSave和buttonRun这两个对象的clicked信号,同时绑定到showMessage()这个槽函数。无论哪一个信号被触发,showMessage()这个槽函数均会被调用,而根据self.sender().text() 这个函数来判断显示的不同内容。
3.信号和槽的连接可以被移除:
1
|
self .buttonDisconnect.clicked.connect( self .unbindConnection) |
当buttonDisconnect信号触发之后,与其关联的槽函数unbindConnection()中就会执行disconnect()方法,如下:
1
2
|
def unbindConnection( self ): self .slider.valueChanged.disconnect() |
其中执行disconnect()的时候可以指定解除与某个特定的slot槽的关联,比如self.slider.valueChanged.disconnect(self.pBar.setValue),此时解除和QProgressBar的setValue()的关联,如果不指定,将解除和这个信号所有关联的槽。
4、信号与信号的关联:
1
|
self .buttonRun.clicked.connect( self .buttonSave.clicked) |
在样例说明中提到,在运行之前要对样本进行保存,所以为了保证运行的时候执行了保存的操作,所以将buttonRun.clicked信号和buttonSave.clicked信号关联起来。
示例中在没有执行“保存”(buttonSave)的时候,执行“运行”(buttonRun),此时由于两个对象的clicked信号已经关联,所以buttonSave的clicked同样会执行。
最终结果:
本文是《从零开始学PyQt5》第五篇,希望小伙伴们可以多多支持,一起学习!
参考:
Pyqt5系列(七)-信号与槽机制_追逐阳光的风-CSDN博客_pyqt5信号和槽
到此这篇关于PyQt5信号与槽机制案例详解的文章就介绍到这了,更多相关PyQt5信号与槽机制内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://blog.csdn.net/kobepaul123/article/details/122934359