1.4.2 一个信号连接一个槽
我们可以在很多窗口上看到“Start”按钮,单击之后文本从“Start”变成了“Stop”,示例代码1-13通过信号和槽机制实现了这种功能。
示例代码1-13
import sys
from PyQt5.QtWidgets import *
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.btn = QPushButton('Start', self) #注释1开始
self.btn.clicked.connect(self.change_text) #注释1结束
def change_text(self): # 2
if self.btn.text() == 'Start'
self.btn.setText('Stop')
else:
self.btn.setText('Start')
if __name__ == '__main__':
app = QApplication([])
window = Window()
window.show()
sys.exit(app.exec())
运行结果如图1-22所示。
图1-22 改变按钮文本
代码解释:
#1 实例化一个QPushButton按钮控件之后,我们将按钮的clicked信号与自定义的change_text()槽函数连接起来。
#2 在槽函数中,我们首先通过text()方法获取到当前单击按钮的文本,如果是“Start”,就调用setText()方法将按钮的文本修改为“Stop”。而如果文本是“Stop”,就将其修改为“Start”。
因为要在槽函数中使用btn对象,所以应该在类的初始化函数__init__()中将btn设置为成员变量,也就是self.btn。当然我们也可以直接通过sender()方法获取到当前发射信号的控件对象,代码如下所示。
import sys
from PyQt5.QtWidgets import *
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
btn = QPushButton('Start', self)
btn.clicked.connect(self.change_text)
def change_text(self):
btn = self.sender()
if btn.text() == 'Start':
btn.setText('Stop')
else:
btn.setText('Start')
... # 程序入口代码不变
每个控件都有相应的内置信号,比如QPushButton控件有clicked、pressed、released等内置信号。当然我们也可以给控件或窗口自定义一个信号,笔者会在1.4.6小节中讲解。
信号是可以传值的,比如QLineEdit控件有一个textChanged信号,它会在输入框中的文本发生改变时被发射,并且会携带当前的文本。图1-23所示为官方文档中对该信号的解释,示例代码1-14演示了该信号的使用方法。
图1-23 textChanged信号
示例代码1-14
import sys
from PyQt5.QtWidgets import *
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.resize(180, 30)
line = QLineEdit(self)
line.textChanged.connect(self.show_text)
def show_text(self, text): # 1
print(text)
if __name__ == '__main__':
app = QApplication([])
window = Window()
window.show()
sys.exit(app.exec())
运行结果如图1-24所示。
图1-24 控制台输出
代码解释:
#1 show_text()槽函数有一个text参数,textChanged信号携带的值会传给这个参数。运行程序,每当修改输入框中的文本时,控制台都会将修改后的文本输出。
如果信号(比如clicked信号)无法传值,而我们想要让它连接一个带参数的槽函数,这时候要怎么做呢?答案是使用lambda匿名函数。示例代码1-15演示了如何通过lambda匿名函数让clicked信号连接setText()这个带参数的槽函数。
示例代码1-15
import sys
from PyQt5.QtWidgets import *
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
btn = QPushButton('Start', self)
btn.clicked.connect(lambda: btn.setText('Stop')) # 1
if __name__ == '__main__':
app = QApplication([])
window = Window()
window.show()
sys.exit(app.exec())
代码解释:
#1 如果我们把此处的信号和槽连接代码更改成“btn.clicked.connect(btn.setText ('Stop'))”,那么程序就会报错,如图1-25所示。
图1-25 报错截图
在信号和槽连接时,我们必须往connect()方法中传入一个可调用对象,也就是传入函数名,不带括号。如果带了括号,就表示我们传入了函数的执行结果。setText('Stop')方法执行后返回None,信号跟None连接明显不合理。如果要将setText()用作和clicked信号连接的槽函数,就必须使用lambda匿名函数把setText()方法“包装”一下,以返回一个可调用对象。