PyQt编程快速上手
上QQ阅读APP看书,第一时间看更新

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()方法“包装”一下,以返回一个可调用对象。