PyQt5 – 信号和插槽

  • Post category:Python

PyQt5是一种在Python中使用Qt GUI应用程序框架的工具包。在PyQt5中,信号和插槽用于在不同的对象之间进行通信。本文将详细介绍PyQt5中信号和插槽的使用攻略。

一、信号和插槽的介绍

信号:在PyQt5中,信号是QWidget和QMainWindow等对象的一种特殊方法,用于通知其他对象发生事件或状态变化。

插槽:在PyQt5中,插槽是与信号相关联的方法。当一个信号发出时,与之相关联的插槽方法会被自动调用。

二、信号和插槽的基本概念

1.信号的定义

在PyQt5中,我们使用以下格式来定义一个信号:

信号 = pyqtSignal(参数)

示例代码:

from PyQt5.QtCore import pyqtSignal, QObject

class SignalDemo(QObject):
    signal1 = pyqtSignal(int, int)  # 将新增一个有两个整型参数的信号

在上面的代码中,我们定义了一个名为signal1的信号,该信号将具有两个整型参数。

2.信号的连接

在PyQt5中,可以通过connect()方法将一个信号连接到一个插槽上,从而实现信号的调用。

信号.connect(插槽)

示例代码:

from PyQt5.QtCore import pyqtSignal, QObject

class SignalDemo(QObject):
    signal1 = pyqtSignal(int, int)  # 定义一个有两个整型参数的信号

    def __init__(self, parent=None):
        super().__init__(parent)

        self.signal1.connect(self.slot_method)  # 将信号连接到插槽上

    def slot_method(self, val1, val2):
        print('slot method receives: {} {}'.format(val1, val2))

在上面的代码中,我们定义了一个名为SignalDemo的类,该类中有一个名为signal1的信号,我们将其使用connect()方法连接到了一个名为slot_method的插槽上。

3.信号的发射

在PyQt5中,我们可以使用emit()方法来发射一个信号。

信号.emit(参数)

示例代码:

from PyQt5.QtCore import pyqtSignal, QObject

class SignalDemo(QObject):
    signal1 = pyqtSignal(int, int)

    def __init__(self, parent=None):
        super().__init__(parent)

        self.signal1.connect(self.slot_method)

    def slot_method(self, val1, val2):
        print('slot method receives: {} {}'.format(val1, val2))

    def emit_signal(self):
        self.signal1.emit(1, 2)  # 发射名为signal1的信号,参数为1和2

三、示例说明

下面我们使用两个简单的实例来说明信号和插槽的使用。

1.实例一

该实例演示了如何使用PyQt5的信号和插槽机制来进行计数器的加减操作。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout, QVBoxLayout, QPushButton
from PyQt5.QtCore import QThread, pyqtSignal

class CounterThread(QThread):
    counterChanged = pyqtSignal(int)

    def __init__(self, parent=None):
        super().__init__(parent)

        self._counter = 0

    def increment(self):
        self._counter += 1
        self.counterChanged.emit(self._counter)

    def decrement(self):
        self._counter -= 1
        self.counterChanged.emit(self._counter)

class CounterWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self._counter = 0

        self.counterLabel = QLabel(str(self._counter))
        self.incrementButton = QPushButton('+')
        self.decrementButton = QPushButton('-')

        layout = QHBoxLayout()
        layout.addWidget(self.counterLabel)
        layout.addWidget(self.incrementButton)
        layout.addWidget(self.decrementButton)

        self.setLayout(layout)

        self.counterThread = CounterThread()
        self.counterThread.counterChanged.connect(self.updateCounter)

        self.incrementButton.clicked.connect(self.counterThread.increment)
        self.decrementButton.clicked.connect(self.counterThread.decrement)

    def updateCounter(self, val):
        self._counter = val
        self.counterLabel.setText(str(self._counter))

class MainWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.counterWidget1 = CounterWidget()
        self.counterWidget2 = CounterWidget()

        layout = QVBoxLayout()
        layout.addWidget(self.counterWidget1)
        layout.addWidget(self.counterWidget2)

        self.setLayout(layout)

if __name__ == '__main__':
    app = QApplication(sys.argv)

    mainWidget = MainWidget()
    mainWidget.show()

    sys.exit(app.exec_())

在这个实例中,我们创建了一个CounterThread类,该类继承自QThread,定义了一个增加(increment)和减少(decrement)计数器的方法,并发射了一个counterChanged信号。我们还创建了一个CounterWidget类作为GUI界面的主要部分,其次还有一个MainWidget类,它将两个CounterWidgets添加到垂直布局中。当我们单击CounterWidget的增加或减少按钮时,将调用CounterThread的increment或decrement方法,并将counterChanged发射的信号连接到更新计数器标签上的插槽。

2.实例二

该实例演示了如何将按键事件转化为PyQt5信号并将其传递给插槽。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtCore import Qt, pyqtSignal

class SignalWidget(QWidget):
    signalKeyA = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_A:
            self.signalKeyA.emit()

class MainWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.label = QLabel('Press the A key to emit signal')
        self.signalWidget = SignalWidget()

        layout = QVBoxLayout()
        layout.addWidget(self.label)
        layout.addWidget(self.signalWidget)
        self.setLayout(layout)

        self.signalWidget.signalKeyA.connect(self.handleSignal)

    def handleSignal(self):
        self.label.setText('Signal received')

if __name__ == '__main__':
    app = QApplication(sys.argv)

    mainWidget = MainWidget()
    mainWidget.show()

    sys.exit(app.exec_())

在这个实例中,我们创建了一个名为SignalWidget的QWidget类,它重构了keyPressEvent方法来生成名为signalKeyA的信号。在MainWidget中,我们将SignalWidget添加到容器中,并将其signalKeyA信号连接到handleSignal插槽上。当用户按下A键时,SignalWidget将发射该信号,并将发射的信号通过连接和调用将触发handleSignal方法,从而更改标签文本。