PyQt5—信号与槽

信号与槽

  • PyQt5 的信号与槽
    • 一、基础理论
      • 1、定义信号
        • 1.1、为 QObject 对象创建信号
        • 1.2、为控件创建信号
      • 2、操作信号
      • 3、信号与槽的简单应用
        • 3.1、内置信号与槽的使用
        • 3.2、自定义信号和槽使用
    • 二、信号与槽进阶
      • 1、内置信号和自定义槽函数
      • 2、自定义信号和内置槽函数
    • 三、高级信号与槽
      • 1、高级自定义信号和槽
      • 2、使用自定义参数
      • 3、装饰器信号与槽

PyQt5 的信号与槽

一、基础理论

  • 信号和槽,是 PyQt5 程序中对象之间进行通信的机制;每个 QObject 对象和 QWidget 控件都支持信号和槽机制;信号与槽通过 object.signal.connect() 函数连接;PyQt5 除了很多内置的信号,还支持自定义信号。
  • 信号与槽,有以下特点:
    1)一个信号可以连接多个槽。
    2)信号之间可以相互连接。
    3)信号参数可以是任何 Python 类型。
    4)一个槽可以监听多个信号。
    5)信号与槽既可以同步连接也可以异步连接。
    6)信号与槽的连接可能跨线程,信号可能会断开。

1、定义信号

  • 使用 PyQt5.QtCore.pyqtSignal() 函数可以为 QObject 创建信号,并把信号定义为类的属性。

1.1、为 QObject 对象创建信号

  • 使用 pyqtSignal() 函数创建一个或多个重载的未绑定的信号作为类的属性,并且信号必须在类创建时定义,并且只能在 QObject 的子类中定义。

1.2、为控件创建信号

  • pyqtSignal() 函数也支持为控件创建信号,如: btnclickedSignal = pyqtSignal()。

2、操作信号

  • 使用 connect() 函数可以将信号绑定到槽函数上;使用 disconnect() 函数可以接触信号和槽之间的绑定。

3、信号与槽的简单应用

  • 信号与槽有三种使用方式:内置信号与槽的使用,自定义信号与槽的使用和装饰器的信号与槽的使用。

3.1、内置信号与槽的使用

  • 使用案例代码如下:
    # -*- coding:utf-8 -*-
    # Time : 2019/09/10 下午 8:29 
    # Author : 御承扬
    # e-mail:[email protected]
    # project:  PyQt5
    # File : SingleSlot01.py 
    # @software: PyCharm
    
    
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    import sys
    
    if __name__ == "__main__":
        app = QApplication([])
        widget = QWidget()
        widget.setWindowTitle('内置信号示例')
        widget.setWindowIcon(QIcon("./images/Python2.ico"))
        widget.resize(350, 150)
    
        def showMSG():
            QMessageBox.information(widget, "信息提示框", "OK,弹出测试信息")
    
        btn = QPushButton("测试按钮", widget)
        btn.clicked.connect(showMSG)
        widget.show()
        sys.exit(app.exec_())
    
  • 效果如下:
    PyQt5—信号与槽_第1张图片

3.2、自定义信号和槽使用

  • 所谓使用自定义信号和槽,就是指在发射信号时,不使用窗口控件的函数,使用自定义函数。
  • 示例代码如下:
    # -*- coding:utf-8 -*-
    # Time : 2019/09/10 下午 8:56 
    # Author : 御承扬
    # e-mail:[email protected]
    # project:  PyQt5
    # File : pyqtSignalTest.py 
    # @software: PyCharm
    
    
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    import sys
    
    
    # 信号对象
    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()
        print('-----把信号绑定到槽函数上------')
        send.sendMsg.connect(slot.get)
        send.run()
        print('-----把信号与槽函数的连接断开----')
        send.sendMsg.disconnect(slot.get)
        send.run()
    
  • 控制台输出:
    -----把信号绑定到槽函数上------
    QSlot get msg =>Hello PyQt5
    -----把信号与槽函数的连接断开----
    
  • 如果要传递对个参数,其写法也是类似的,只需将 sendMsg = pyqtSignal(object) 改成 sendMsg = pyqtSignal(str, str)。

二、信号与槽进阶

  • 内置信号也可以和自定义槽函数结合使用,简单来说就是自定义的信号和槽可以内置的信号和槽搭配使用。

1、内置信号和自定义槽函数

  • 信号使用 PyQt5 内置的,而槽函数自定义,示例代码如下:
    # -*- coding:utf-8 -*-
    # Time : 2019/09/11 下午 3:52 
    # Author : 御承扬
    # e-mail:[email protected]
    # project:  PyQt5
    # File : SignalSlot02.py 
    # @software: PyCharm
    
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import *
    import sys
    
    
    class WinForm(QWidget):
        def __init__(self, parent=None):
            super(WinForm, self).__init__(parent)
            self.setWindowIcon(QIcon("./images/Python2.ico"))
            self.setWindowTitle('内置信号和自定义槽函数')
            self.resize(330, 50)
            btn = QPushButton('关闭', self)
            btn.clicked.connect(self.btn_close)
    
        def btn_close(self):
            self.close()
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        win = WinForm()
        win.show()
        sys.exit(app.exec_())
    

2、自定义信号和内置槽函数

  • 示例代码如下:
    # -*- coding:utf-8 -*-
    # Time : 2019/09/13 下午 8:37 
    # Author : 御承扬
    # e-mail:[email protected]
    # project:  PyQt5
    # File : SignalSlot03.py
    # @software: PyCharm
    
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    import sys
    
    
    class WinForm(QWidget):
        button_clicked_signal = pyqtSignal()
    
        def __init__(self, parent=None):
            super(WinForm, self).__init__(parent)
            self.setWindowTitle('自定义信号和内置槽函数示例')
            self.setWindowIcon(QIcon("./images/Python2.ico"))
            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、高级自定义信号和槽

  • 高级自定义信号与槽,指的是根据程序的需要和自己的风格定义信号和槽,其步骤如下:
    1)定义信号
    2)定义槽函数
    3)连接信号和槽函数
    4)发射信号
  • 示例代码如下:
    # -*- coding:utf-8 -*-
    # Time : 2019/09/15 下午 4:00 
    # Author : 御承扬
    # e-mail:[email protected]
    # project:  PyQt5
    # File : SignalSlot04.py 
    # @software: PyCharm
    
    
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    import sys
    
    
    class CustomSignal(QObject):
        # 声明无参信号
        signal1 = pyqtSignal()
        # 声明带一个 int 型参数的信号
        signal2 = pyqtSignal(int)
        # 声明一个带 int 型和 str 型的参数的信号
        signal3 = pyqtSignal(int, str)
        # 声明一个带列表类型的参数的信号
        signal4 = pyqtSignal(list)
        # 声明一个带字典类型参数的信号
        signal5 = pyqtSignal(dict)
        # 声明一个多重载版本的信号
        signal6 = pyqtSignal([int, str], [str])
    
        def __init__(self, parent=None):
            super(CustomSignal, self).__init__(parent)
            # 将信号连接到指定槽函数
            self.signal1.connect(self.signalCall1)
            self.signal2.connect(self.signalCall2)
            self.signal3.connect(self.signalCall3)
            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(2)
            self.signal3.emit(1, "text")
            self.signal4.emit([1, 2, 3, 4])
            self.signal5.emit({"name": "solder", "age": "24"})
            self.signal6[int, str].emit(1, "text")
            self.signal6[str].emit("text")
    
        def signalCall1(self):
            print("signal1 emit")
    
        def signalCall2(self, val):
            print("signal2 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__":
        test = CustomSignal()
    
  • 控制台输出:
    signal1 emit
    signal2 emit, value: 2
    signal3 emit, value: 1 text
    signal4 emit, value: [1, 2, 3, 4]
    signal5 emit, value: {'name': 'solder', 'age': '24'}
    signal6 emit, value: 1 text
    signal6 overload emit, value: text
    

2、使用自定义参数

  • 在使用自定义参数时,为了避免信号发出的参数个数为 0,槽函数接收的参数个数为 1,可以使用 lambda 表达式和 functools 的 partial 函数。
  • lambda 表达式示例如下:
    # -*- coding:utf-8 -*-
    # Time : 2019/09/15 下午 4:38 
    # Author : 御承扬
    # e-mail:[email protected]
    # project:  PyQt5
    # File : SignalSlot5.py 
    # @software: PyCharm
    
    
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    import sys
    
    
    class WinForm(QMainWindow):
        def __init__(self, parent=None):
            super(WinForm, self).__init__(parent)
            self.setWindowIcon(QIcon("./images/Python2.ico"))
            self.setWindowTitle('Signal Demo')
            button1 = QPushButton('Button 1')
            button2 = QPushButton('Button 2')
            button1.clicked.connect(lambda: self.onButtonClick(1))
            button2.clicked.connect(lambda: self.onButtonClick(2))
            layout = QHBoxLayout()
            layout.addWidget(button1)
            layout.addWidget(button2)
            main_frame = QWidget()
            main_frame.setLayout(layout)
            self.setCentralWidget(main_frame)
    
        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_())
    
  • 运行效果如下:
    PyQt5—信号与槽_第2张图片
  • 使用 functools 的 partial 函数,只需对上述代码稍作修改
    button1.clicked.connect(partial(self.onButtonClick, 1))
    button2.clicked.connect(partial(self.onButtonClick, 2))
    

3、装饰器信号与槽

  • 通过装饰器的方法定义信号和槽,使用形式如下:
    @PyQt5.QtCore.pyqtSlot(参数)
    def on_发送者对象名称_发送信号名称(self, 参数):
    	pass
    
  • 在使用该方法之前,必须先执行如下语句:
    QMetaObject.connectSlotByName(QObject)
    
  • 使用示例:
    # -*- coding:utf-8 -*-
    # Time : 2019/09/15 下午 8:13 
    # Author : 御承扬
    # e-mail:[email protected]
    # project:  PyQt5
    # File : SignalSlot06.py 
    # @software: PyCharm
    
    from PyQt5 import QtCore
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    import sys
    
    
    class CustomWidget(QWidget):
        def __init__(self, parent=None):
            super(CustomWidget, self).__init__(parent)
            self.setWindowTitle('SignalSlot Demo')
            self.setWindowIcon(QIcon("./images/Python2.ico"))
            self.okButton = QPushButton("ok", self)
            self.okButton.setObjectName("okButton")
            layout = QHBoxLayout()
            layout.addWidget(self.okButton)
            self.setLayout(layout)
            QtCore.QMetaObject.connectSlotsByName(self)
    
        @QtCore.pyqtSlot()
        def on_okButton_clicked(self):
            QMessageBox.information(self, "信息提示框", "单击了ok按钮")
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        win = CustomWidget()
        win.show()
        sys.exit(app.exec_())
    

你可能感兴趣的:(PyQt5)