• PyQt5 信号(Signal)与槽(Slot)


    信号与槽介绍

    信号(Signal)与槽(Slot)是Qt中的核心机制,也是在PyQt编程中对象之间进行通信的机制。PyQt的窗口控件类有很多内置信号,开发者也可以添加自定义信号。信号与槽有如下特点:

    • 一个信号可以连接多个槽。
    • 一个信号可以连接另一个信号。
    • 信号参数可以使任何Python类型。
    • 一个槽可以连接到多个信号。
    • 信号与槽的连接方式可以是同步连接,也可以是异步连接。
    • 信号与槽的连接可能会跨线程。
    • 信号可以断开连接。

    内置信号与槽的使用

    这里演示了内置clicked信号连接槽函数的使用

    import sys
    from PyQt5.QtWidgets import QPushButton, QApplication, QWidget, QMessageBox
    
    app = QApplication(sys.argv)
    widget = QWidget()
    
    def showMsg():
        QMessageBox.information(widget, "信息提示框", "Ok,弹出测试信息")
    
    btn = QPushButton("测试点击按钮", widget)
    btn.clicked.connect(showMsg)
    
    widget.show()
    sys.exit(app.exec_())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    自定义信号与槽的使用

    import sys
    from PyQt5.QtCore import QObject, pyqtSignal
    
    
    # 信号对象
    class QTypeSignal(QObject):
        # 定义一个信号
        sendmsg = pyqtSignal(object)
    
        def __init__(self):
            super(QTypeSignal, self).__init__()
        
        def run(self):
            # 发射信号
            self.sendmsg.emit('Hello PyQt5')
    
    # 槽对象
    class QTypeSlot(QObject):
        def __init__(self):
            super(QTypeSlot, self).__init__()
    
        # 槽对象中的槽函数
        def get(self, msg):
            print("QSlot get msg => " + msg)
    
    if __name__ == "__main__":
        send = QTypeSignal()
        slot = QTypeSlot()
    
        # 1
        print("---把信号绑定到槽函数上---")
        send.sendmsg.connect(slot.get)
        send.run()
    
        # 2 
        print('---把信号与槽函数断开---')
        send.sendmsg.disconnect(slot.get)
        send.run()
    
    • 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

    在这里插入图片描述

    自定义信号和内置槽函数

    import sys
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5.QtCore import Qt
    
    class WinForm (QWidget):
        # 自定义信号,不带参数
        button_clicked_signal = pyqtSignal()
    
        def __init__(self, parent=None):
            super(WinForm, self).__init__(parent)
            self.setWindowTitle("自定义信号和内置槽函数示例")
            self.resize(330, 50)
            btn = QPushButton("关闭", self)
    
            # 连接信号与槽函数
            btn.clicked.connect(self.btn_clicked)
            
            # 接收信号,连接到槽函数
            self.button_clicked_signal.connect(self.close)
    
        def btn_clicked(self):
            # 发送自定义信号,无参数
            self.button_clicked_signal.emit()
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        win = WinForm()
        win.show()
        sys.exit(app.exec_())
    
    • 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

    自定义信号和自定义槽函数

    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    
    class WinForm(QWidget):
        # 自定义信号,无参数
        button_clicked_signal = pyqtSignal()
        def __init__(self, parent= None):
            super(WinForm, self).__init__(parent)
            self.setWindowTitle("自定义信号和槽函数示例")
            self.resize(350, 50)
    
            btn = QPushButton("关闭", self)
            btn.clicked.connect(self.btn_clicked)
            self.button_clicked_signal.connect(self.btn_close)
        
        def btn_clicked(self):
            self.button_clicked_signal.emit()
    
        def btn_close(self):
            self.close()
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        win = WinForm()
        win.show()
        sys.exit(app.exec_())    
    
    • 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

    自定义有参信号

    import sys
    from PyQt5.QtCore import pyqtSignal, QObject
    
    class CustSignal(QObject):
        # 声明无参数的信号
        signal1 = pyqtSignal()
    
        # 声明带一个int类型参数的信号
        signal2 = pyqtSignal(int)
    
        # 声明带一个int和一个str类型参数的信号
        signal3 = pyqtSignal(int, str)
    
        # 声明带一个列表类型参数的信号
        signal4 = pyqtSignal(list)
    
        # 声明带一个字典类型参数的信号
        signal5 = pyqtSignal(dict)
    
        # 声明一个多重载版本的信号,包括带int和str类型参数的信号和带str类型参数的信号
        signal6 = pyqtSignal([int,str], [str])
    
        def __init__(self, parent=None):
            super(CustSignal, self).__init__(parent)
            
            # 将信号连接到指定的槽函数
            self.signal1.connect(self.signalCall1)
            self.signal2.connect(self.signalCall2)
            self.signal3.connect(self.signalCall4)
            self.signal4.connect(self.signalCall4)
            self.signal5.connect(self.signalCall5)
            self.signal6[int, str].connect(self.signalCall6)
            self.signal6[str].connect(self.signalCall6OverLoad)
    
            # 发射信号
            self.signal1.emit()
            self.signal2.emit(100)
            self.signal3.emit(200, 'hello')
            self.signal4.emit([1,2,3,4,5,6])
            self.signal5.emit({"name":"xiaowang", "age":"25"})
            self.signal6[int, str].emit(300, 'hello world')
            self.signal6[str].emit('hello pyqt')
    
        def signalCall1(self):
            print('signal1 emit')
        
        def signalCall2(self, val):
            print('signal3 emit, value:', val)
        
        def signalCall3(self, val, text):
            print('signal3 emit, value:', val, text)
    
        def signalCall4(self, val):
            print('signal4 emit, value:', val)
        
        def signalCall5(self, val):
            print('signal5 emit, value:', val)
    
        def signalCall6(self, val, text):
            print('signal6 emit, value:', val, text)
    
        def signalCall6OverLoad(self, val):
            print('signal6 overload emit, value:', val)
    
    if __name__ == "__main__":
        custSignal = CustSignal()
      
    
    • 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

    使用自定义信号参数

    对于clicked信号来说他是没有参数的,如果连接的槽函数希望可以接收参数,如果直接连接有参数的槽函数会出错,因为信号发出的参数个数一定要大于槽函数接收的参数个数。这里有两种解决方法:

    • 1.使用lambda
    • 2.使用functools模块中的partial函数
    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    from functools import partial, partialmethod
    
    class WinForm(QMainWindow):
        def __init__(self, parent=None):
            super(WinForm, self).__init__(parent)
            self.setWindowTitle("有参槽函数接收无参信号的解决方法")
    
            button1 = QPushButton("Button 1")
            button2 = QPushButton("Button 2")
    
            # 对于clicked信号来说他是没有参数的,如果连接的槽函数希望可以接收参数,如果直接连接有参数
            # 的槽函数会出错,因为信号发出的参数个数一定要大于槽函数接收的参数个数。这里有两种解决方法:
            # 1.使用lambda
            # 2.使用functools模块中的partial函数
            
            # 使用lambda
            button1.clicked.connect(lambda: self.onButtonClick(1))
    
            # 使用functools模块中的partial函数
            button2.clicked.connect(partial(self.onButtonClick, 2))
    
            layout = QHBoxLayout()
            layout.addWidget(button1)
            layout.addWidget(button2)
            mainwidget = QWidget()
            mainwidget.setLayout(layout)
            self.setCentralWidget(mainwidget)
    
    
        def onButtonClick(self, n):
            print("Button {0} 被按下了".format(n))
            QMessageBox.information(self, "信息提示框", 'Button {0} clicked'.format(n))
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        win = WinForm()
        win.show()
        sys.exit(app.exec_())
    
    • 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

    装饰器信号与槽

    装饰器信号与槽
    @PyQt5.QtCore.pyqtSlot(参数)
    def on_发送者对象名称_发射信号名称(self, 参数):
    pass
    必须先执行了这行代码:QtCore.QMetaObject.connectSlotsByName(self)

    from PyQt5 import QtCore
    from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QMessageBox
    import sys
    
    # 装饰器信号与槽
    # @PyQt5.QtCore.pyqtSlot(参数)
    # def on_发送者对象名称_发射信号名称(self, 参数):
    #   pass
    # 
    # 必须要先执行这行代码:QtCore.QMetaObject.connectSlotsByName(self)
    
    class CustWidget(QWidget):
        def __init__(self, parent=None):
            super(CustWidget, self).__init__(parent)
            self.setWindowTitle("装饰器信号与槽Demo")
            self.resize(350, 50)
    
            self.okButton = QPushButton("OK", self)
    
            # 使用setObjectName设置对象名称
            self.okButton.setObjectName("okButton")
            layout = QHBoxLayout()
            layout.addWidget(self.okButton)
            self.setLayout(layout)
    
            QtCore.QMetaObject.connectSlotsByName(self)
    
    
        @QtCore.pyqtSlot()
        def on_okButton_clicked(self):
            print("单击了OK按钮")
            QMessageBox.information(self, "信息提示框", "单击了OK按钮")
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        win = CustWidget()
        win.show()
        sys.exit(app.exec_())
    
    • 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

    信号与槽的断开和连接

    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import *
    
    
    # 信号与槽断开连接
    
    class SignalClass(QObject):
        # 声明无参数的信号
        signal1 = pyqtSignal()
    
        # 声明带一个int类型参数的信号
        signal2 = pyqtSignal(int)
    
        def __init__(self, parent=None):
            super(SignalClass, self).__init__(parent)
    
            # 将信号signal1连接到sig1Call和sig2Call这两个槽函数
            self.signal1.connect(self.sig1Call)
            self.signal1.connect(self.sig2Call)
    
            # 将signal2连接到signal1
            self.signal2.connect(self.signal1)
    
            # 发射信号
            self.signal1.emit()
            self.signal2.emit(1)
    
            # 断开signal1,signal2信号与各槽函数的连接
            self.signal1.disconnect(self.sig1Call)
            self.signal1.disconnect(self.sig2Call)
            self.signal2.disconnect(self.signal1)
            
            # 将信号signal1和signal2连接到同一个槽函数sig1Call
            self.signal1.connect(self.sig1Call)
            self.signal2.connect(self.sig1Call)
    
            # 再次发射信号
            self.signal1.emit()
            self.signal2.emit(2)
    
        def sig1Call(self):
            print('signal-1 emit')
        
        def sig2Call(self):
            print('signal-2 emit')
    
    if __name__ == "__main__":
        signal = SignalClass()
    
    • 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

    多线程中信号与槽的使用

    import sys
    from PyQt5.QtWidgets import QApplication, QWidget
    from PyQt5.QtCore import QThread, pyqtSignal
    
    class Main(QWidget):
        def __init__(self, parent=None):
            super(Main, self).__init__(parent)
    
            # 创建一个线程实例并设置名称,变量,信号与槽
            self.thread = MyThread()
            self.thread.setIdentity("thread1")
            self.thread.sinOut.connect(self.outText)
            self.thread.setVal(6)
            
        def outText(self, text):
            print(text)
    
    class MyThread(QThread):
        
        sinOut = pyqtSignal(str)
    
        def __init__(self, parent=None):
            super(MyThread, self).__init__(parent)
            self.identity = None
    
        def setIdentity(self, text):
            self.identity = text
        
        def setVal(self, val):
            self.times = int(val)
            # 执行线程run方法
            self.start()
    
        def run(self):
            while self.times > 0 and self.identity:
                # 发射信号
                self.sinOut.emit(self.identity + "==>" + str(self.times))
                self.times -= 1
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        main = Main()
        main.show()
        sys.exit(app.exec_())
    
    • 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
  • 相关阅读:
    leetcode:768. 最多能完成排序的块 II【排列 + sortedlist】
    Python3,os模块还可以这样玩,自动删除磁盘文件,非必要切勿操作。
    搜索排序技术简介
    卷积神经网络应用实例,卷积神经网络实际应用
    Apache网页优化
    【论文精读】Counterfactual Explainable Recommendation
    卓岚联网模块连接三菱FX系列PLC应用实例
    企业为什么做不好生产计划?
    入坑机器学习:三,非监督学习
    锚点 smooth-scrolljs库 平滑滚动 / scrollIntoView
  • 原文地址:https://blog.csdn.net/u013420428/article/details/128083678