03:pyqt5的信号与槽函数

1.是什么

其实这个机制非常好理解,我们拿红绿灯来做个类比。

当红灯信号发射后,行人就会停下;当绿灯信号发射后,行人就会前进。我们用red和green来表示信号,用stop()和go()函数来表示行人的动作,这两个函数也被称为槽函数。

也就是说,当red信号发射后,stop()槽函数就会被调用;当green信号发射后,go()槽函数会被调用。不过信号和槽只有在连接之后才可以起作用,连接方式如图1-21所示

在下图中

(1)widget就是PyQt中的控件对象。其实就是组件

(2)signal就是控件对象拥有的信号

(3)connect()方法用于连接信号和槽,

(4)slot是槽函数名称。

请添加图片描述

red信号stop()槽函数进行连接

green信号go()槽函数进行连接

扫描二维码关注公众号,回复: 16531455 查看本文章

只有这样连接后,发射的信号才可以调用相应的槽函数。

总结起来就一句话:连接后,信号发射,槽函数“启动”

traffic_light.red.connect(stop)
traffic_light.green.connect(go)

在connect()方法中传入的是函数名

2.一个信号连接一个槽

1.案例一:start按钮与stop按钮之间转换

实现功能:我们可以在很多窗口上看到“Start”按钮,单击之后文本从“Start”变成了“Stop”

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')
if __name__ == '__main__':
    app = QApplication([])
    window = Window()
    window.show()
    sys.exit(app.exec())

(#1) 实例化一个QPushButton按钮控件之后,我们将按钮的clicked信号与自定义的change_text()槽函数连接起来。

(#2) 在槽函数中,我们首先通过text()方法获取到当前单击按钮的文本,如果是“Start”,就调用setText()方法将按钮的文本修改为“Stop”。而如果文本是“Stop”,就将其修改为“Start”。

因为要在槽函数中使用btn对象,所以应该在类的初始化函数__init__()中将btn设置为成员变量,也就是self.btn。当然我们也可以直接通过sender()方法获取到当前发射信号的控件对象

每个控件都有相应的内置信号,比如QPushButton控件有clicked、pressed、released等内置信号。当然我们也可以给控件或窗口自定义一个信号

2.案例二:信号传值

信号是可以传值的,比如QLineEdit控件有一个textChanged信号,它会在输入框中的文本发生改变时被发射,并且会携带当前的文本。

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) show_text()槽函数有一个text参数,textChanged信号携带的值会传给这个参数。运行程序,每当修改输入框中的文本时,控制台都会将修改后的文本输出

3.案例三

如果信号(比如clicked信号)无法传值,而我们想要让它连接一个带参数的槽函数,这时候要怎么做呢?答案是使用lambda匿名函数。

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())

在信号和槽连接时,我们必须往connect()方法中传入一个可调用对象,也就是传入函数名,不带括号。

如果带了括号,就表示我们传入了函数的执行结果。

setText(‘Stop’)方法执行后返回None,信号跟None连接明显不合理。

如果要将setText()用作和clicked信号连接的槽函数,就必须使用lambda匿名函数把setText()方法“包装”一下,以返回一个可调用对象。

3.一个信号连接多个槽

一个信号可以连接多个槽函数,也就是信号只用发射一次,就可以调用多个槽函数。

import sys
from PyQt5.QtWidgets import *
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.btn = QPushButton('Start', self)
        self.btn.clicked.connect(self.change_text)  #注释1开始
        self.btn.clicked.connect(self.change_size)  #注释1结束
    def change_text(self):
        if self.btn.text() == 'Start':
            self.btn.setText('Stop')
        else:
            self.btn.setText('Start')
    def change_size(self):    # 2
        self.btn.resize(150, 30)
if __name__ == '__main__':
    app = QApplication([])
    window = Window()
    window.show()
    sys.exit(app.exec())

(#1) clicked信号连接了change_text()槽函数和change_size()槽函数。

(#2) change_size()槽函数用于改变按钮的尺寸

4.多个信号连接一个槽

QPushButton除了有clicked信号,还有pressed信号和released信号。

pressed信号是在按钮被“按下”那一刻发射,而released信号则是在按钮被“松开”后发射。

“按下”和“松开”其实就构成了一次单击,也就会发射clicked信号。

import sys
from PyQt5.QtWidgets import *
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.btn = QPushButton('Start', self)
        self.btn.pressed.connect(self.change_text)     #注释1开始
        self.btn.released.connect(self.change_text)    #注释1结束
    def change_text(self):
        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 将pressed信号和released信号都跟change_text()槽函数连接起来。

那么当按钮被“按下”(不“松开”)时,槽函数就会被调用,按钮文本从“Start”变成了“Stop”。

当“松开”按钮后,槽函数再次被调用,按钮文本从“Stop”变回了“Start”。

5.信号与信号连接

信号不仅可以跟槽函数连接,还可以跟信号连接

import sys
from PyQt5.QtWidgets import *
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.btn = QPushButton('Start', self)
        self.btn.pressed.connect(self.btn.released)    #注释1开始
        self.btn.released.connect(self.change_text)    #注释1结束
    def change_text(self):
        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) 我们将pressed信号同released信号进行连接,而released信号则跟槽函数进行连接。

当按钮被“按下”(不“松开”)后,pressed信号发射,released信号也会马上跟着发射,槽函数就会被执行,改变按钮的文本。

当按钮被“松开”后,released信号再次发射,槽函数再次被调用。

6.自定义信号

在PyQt中,各个控件内置的信号已经能够让我们实现许多功能需求,但是如果想要更加个性化的功能,我们还得借助自定义信号来实现。

本小节会详细介绍如何自定义信号,并通过自定义信号进行传值。

1.创建自定义信号-案例一

自定义信号是通过pyqtSignal来创建的,接下来通过示例代码来演示自定义信号的创建过程。

import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Window(QWidget):
    my_signal = pyqtSignal()                   # 1
    def __init__(self):
        super(Window, self).__init__()
        self.my_signal.connect(self.my_slot)   # 2
    def my_slot(self):
        print(self.width())
        print(self.height())
    def mousePressEvent(self, event):          # 3
        self.my_signal.emit()
if __name__ == '__main__':
    app = QApplication([])
    window = Window()
    window.show()
    sys.exit(app.exec())

(#1) 实例化一个pyqtSignal对象。

(#2) 将自定义信号与my_slot()槽函数连接。

(#3) mousePressEvent()是鼠标按下事件函数,每当鼠标被按下时,该事件函数就会被执行。my_siganl信号调用emit()方法将自己发射出去,这样my_slot()槽函数就会被执行,输出窗口的宽和高。

2.让自定义信号携带值

如果想要获取鼠标指针在窗口上的x坐标和y坐标,可以通过信号将坐标值发送过来

import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Window(QWidget):
    my_signal = pyqtSignal(int, int)       # 1
    def __init__(self):
        super(Window, self).__init__()
        self.my_signal.connect(self.my_slot)
    def my_slot(self, x, y):               # 2
        print(x)
        print(y)
    def mousePressEvent(self, event):      # 3
        x = event.pos().x()
        y = event.pos().y()
        self.my_signal.emit(x, y)
if __name__ == '__main__':
    app = QApplication([])
    window = Window()
    window.show()
    sys.exit(app.exec())

(#1) 要通过自定义信号传值,我们必须在实例化pyqtSignal对象时明确要传递的值的类型。由于x坐标和y坐标都是整型值,因此要给pyqtSignal传入两个int。

(#2 )槽函数也要稍做修改,需要增加两个参数,分别用于接收x坐标和y坐标。

(#3 )现在我们需要在鼠标按下事件中获取鼠标指针的x和y坐标,并通过emit()方法将其随信号一同发射出去。

除了整型值,我们还可以让自定义信号携带其他类型(包括Python语言所支持的值类型和PyQt自定义的数据类型)的值,如下表

请添加图片描述

猜你喜欢

转载自blog.csdn.net/qq_63119830/article/details/130486383