第二章 信号与槽
前言:
信号和槽机制是QT的核心机制,要精通QT编程就必须对信号和槽有所了解。信号和槽是一种高级接口,应用于对象之间的通信,它是QT的核心特性,也是QT区别于其它工具包的重要地方。
信号和槽是用来在对象间传递数据的方法:当一个特定事件发生的时候,signal会被emit出来,slot调用是用来响应相应的signal的。Qt中对象已经包含了许多预定义的signal(基本组件都有各自特有的预定义的信号),根据使用的场景我们可以添加新的signal。Qt的对象中已经包含了许多预定义的槽函数,但我们也根据使用的场景添加新的槽函数。
信号:
当对象的状态发生改变的时候,信号就由该对象发射 (emit) 出去。当一个信号被发射(emit)时候,与其关联的槽函数被立刻执行。其中该对象只负责发送信号,发射该信号的对象并不知道是那个对象在接收这个信号。这样保证了对象与对象之间的低耦合。 如果存在信号和多个槽函数相关联的时候,当信号被发射时,这些槽的执行顺序将会是随机的、不确定的。
槽:
用于接受信号,而且槽只是普通的对象成员函数。当和槽连接的信号被发射时,槽会被调用。一个槽并不知道是否有任何信号与自己相连接。
下面通过几个例子介绍信号与槽函数的使用
2.1 一个信号连接一个槽
很多程序上是有“开始”按钮的,按下去后按钮上的文本就变成了“停止”。下面就是一个示例(之后的代码都会用类来呈现):
1 import sys 2 from PyQt5.QtWidgets import QApplication, QWidget, QPushButton 3 4 5 class Demo(QWidget): # 1 6 def __init__(self): 7 super(Demo, self).__init__() 8 self.button = QPushButton("开始", self) # 2 9 self.button.clicked.connect(self.change_text) # 3 10 11 def change_text(self): 12 self.button.setText("结束") # 4 13 self.button.clicked.disconnect(self.change_text) # 5 14 15 16 if __name__ == '__main__': 17 app = QApplication(sys.argv) 18 demo = Demo() # 6 19 demo.show() # 7 20 sys.exit(app.exec_())
#1. 该类继承QWidget,可以将QWidget看作是一种毛坯房,还没有装修,而我们往其中放入QPushButton、QLabel等控件就相当于在装修这间毛坯房。类似功能还有QMainWindow和QDialog,之后章节再讲述;
#2. 实例化一个QPushButton,因为继承于QWidget,所以self不能忘了(相当于告诉程序这个QPushButton是放在QWidget这个房子中的);
#3. 连接信号与槽函数。self.button就是一个控件,clicked(按钮被点击)是该控件的一个信号,connect()即连接,self.change_text即下方定义的函数(我们称之为槽函数)。所以通用的公式可以是:widget.signal.connect(slot);
#4. 将按钮文本从‘开始’改成‘结束’;
#5. 信号和槽解绑,解绑后再按按钮你会发现控制台不会再输出‘change text’,如果把这行解绑的代码注释掉,你会发现每按一次按钮,控制台都会输出一次‘change text’;
#6. 实例化Demo类;
#7. 使demo可见,其中的控件自然都可见(除非某控件刚开始设定隐藏)
现在用鸣枪和开跑来分析下上面这个例子:按钮控件是裁判,他鸣枪发出信号(clicked),change_text()槽函数运行就是选手开跑。
运行结果:

点击“开始”后文本变为:

2.2 多个信号连接同一个槽
在2.1中一个信号连接一个槽函数,现在研究多个信号连接同一个槽函数
QPushButton还有两个信号是pressed和released,这两个信号解释如下:
pressed: 当鼠标在button上并点击左键的时候,触发信号 。
released: 当鼠标左键被释放的时候触发信号。
所以其实pressed和released两个连起来就是一个完整的clicked。
1 import sys 2 from PyQt5.QtWidgets import QApplication, QWidget, QPushButton 3 4 5 class Demo(QWidget): 6 def __init__(self): 7 super(Demo, self).__init__() 8 self.button = QPushButton("开始", self) 9 self.button.pressed.connect(self.change_text) # 1 10 self.button.released.connect(self.change_text) # 2 11 12 def change_text(self): 13 if self.button.text() == "开始": # 3 14 self.button.setText("结束") 15 else: 16 self.button.setText("开始") 17 18 19 if __name__ == '__main__': 20 app = QApplication(sys.argv) 21 demo = Demo() 22 demo.show() 23 sys.exit(app.exec_())
#1-#2. 将pressed和released信号连接搭配change_text()槽函数上;
#3. 若当前按钮文本为‘开始t’,则将文本改为‘开始’;若为‘结束’,则改为‘结束’。
所以当鼠标点击按钮不放时,发出pressed信号,调用槽函数,将‘开始’文本改为‘结束’;当鼠标放开后释放released信号,再次调用槽函数,将文本改回‘开始’。
运行程序:

点击“开始”释放后:

2.3 一个信号与另一个信号连接
1 import sys 2 from PyQt5.QtWidgets import QApplication, QWidget, QPushButton 3 4 5 class Demo(QWidget): 6 def __init__(self): 7 super(Demo, self).__init__() 8 self.button = QPushButton("开始", self) 9 self.button.pressed.connect(self.button.released) # 1 10 self.button.released.connect(self.change_text) # 2 11 12 def change_text(self): 13 if self.button.text() == "开始": # 3 14 self.button.setText("结束") 15 else: 16 self.button.setText("开始") 17 18 19 if __name__ == '__main__': 20 app = QApplication(sys.argv) 21 demo = Demo() 22 demo.show() 23 sys.exit(app.exec_())
#1- #2. 将pressed信号和released信号连接起来,而released信号则与槽函数连接。这样当点击不放时,pressed信号发出,released信号也会发出,从而启动槽函数。释放鼠标则发出released信号,再次启动槽函数。所以程序运行效果跟2.2小节其实是一样的。
2.4 一个信号连接多个槽函数
信号都为clicked,连接多个槽函数
1 # _*_ coding:utf-8 _*_ 2 import sys 3 from PyQt5.QtWidgets import QApplication, QWidget,QPushButton 4 5 6 class Demo(QWidget): 7 def __init__(self): 8 super(Demo, self).__init__() 9 self.resize(300, 300) # 将窗口大小设置为300*300 10 self.setWindowTitle("demo") # 将窗口名字设置为“demo” 11 self.button = QPushButton('start', self) 12 self.button.clicked.connect(self.change_text) 13 self.button.clicked.connect(self.change_window_size) # 信号clicked连接多个槽函数 14 self.button.clicked.connect(self.change_window_title) 15 16 def change_text(self): # 改变文本内容 17 self.button.setText("stop") 18 self.button.clicked.disconnect(self.change_text) 19 20 def change_window_size(self): # 改变窗口大小 21 self.resize(500, 500) 22 self.button.clicked.disconnect(self.change_window_size) 23 24 def change_window_title(self): # 改变窗口名称 25 self.setWindowTitle("槽函数示例") 26 self.button.clicked.disconnect(self.change_window_title) 27 28 29 if __name__ == '__main__': 30 app = QApplication(sys.argv) 31 demo = Demo() 32 demo.show() 33 sys.exit(app.exec_())
2.5 自定义信号
浙公网安备 33010602011771号