PyQt5的信号和槽
程序员文章站
2022-07-13 22:31:55
...
普通用法
给出一个一般的自定义的绑定方式。注意类方法、静态方法和普通方法的区别。如果普通方法作为槽,那么只有绑定了的对应的实例才可以收到信号。其余两个定义后,不需要实例也可以收到。
下面的例子中,receiver1
无法接收信号。
from PyQt5.QtCore import pyqtSignal, QObject
class Sender(QObject):
sendmsg = pyqtSignal(object) # 这里表明有一个参数
def __init__(self):
super(Sender, self).__init__()
def send_msg(self):
self.sendmsg.emit("Hello qt5")
class Receiver(QObject):
def __init__(self):
super(Receiver, self).__init__()
def plain_func(self, msg):
print("plain_func msg: ", msg)
@classmethod
def class_func(cls, msg):
print("class_func msg: ", msg)
@staticmethod
def static_func(msg):
print("static_func msg: ", msg)
receiver = Receiver()
receiver1 = Receiver()
sender = Sender()
sender.sendmsg.connect(receiver.plain_func) # 注意这里是实例
sender.sendmsg.connect(Receiver.class_func)
sender.sendmsg.connect(Receiver.static_func)
sender.send_msg()
输出结果:
plain_func msg: Hello qt5
class_func msg: Hello qt5
static_func msg: Hello qt5
进阶用法
信号和槽的参数重载
from PyQt5.QtCore import QObject, pyqtSignal
class Sender(QObject):
signal_NoParameter = pyqtSignal()
signal_OneParameter = pyqtSignal(int)
signal_OneParameterOverload = pyqtSignal([int], [str])
signal_TwoParameter = pyqtSignal(int, str)
signal_TwoParameterOverload = pyqtSignal([int, int], [int, str])
def __init__(self):
super(Sender, self).__init__()
class Receiver(QObject):
def __init__(self):
super(Receiver, self).__init__()
def setValue_NoParameter(self):
print("No Parameter")
def setValue_OneParameter(self, msg):
print("One Parameter: ", msg)
def setValue_OneParameterOverload(self, msg):
print("One Parameter Overload, msg:", msg, "msg type: ", type(msg))
def setValue_TwoParameter(self, msg1, msg2):
print("Two Parameter, msg1:", msg1, ", msg2: ", msg2)
def setValue_TwoParameterOverload(self, msg1, msg2):
print("Two Parameter Overload, msg1:", msg1, ",msg1 type: ", type(msg1),
"; msg2:", msg2, ", msg2 type: ", type(msg2))
sender = Sender()
receiver = Receiver()
# 关联信号和槽
sender.signal_NoParameter.connect(receiver.setValue_NoParameter)
sender.signal_OneParameter.connect(receiver.setValue_OneParameter)
sender.signal_OneParameterOverload[int].connect(receiver.setValue_OneParameterOverload)
sender.signal_TwoParameter.connect(receiver.setValue_TwoParameter)
sender.signal_TwoParameterOverload[int, int].connect(receiver.setValue_TwoParameterOverload)
# 发射信号测试
sender.signal_NoParameter.emit()
sender.signal_OneParameter.emit(1)
sender.signal_OneParameterOverload.emit(2)
sender.signal_TwoParameter.emit(2, "World")
sender.signal_TwoParameterOverload.emit(1, 2)
输出结果
No Parameter
One Parameter: 1
One Parameter Overload, msg: 2 msg type: <class 'int'>
Two Parameter, msg1: 2 , msg2: World
Two Parameter Overload, msg1: 1 ,msg1 type: <class 'int'> ; msg2: 2 , msg2 type: <class 'int'>
使用自定义的参数
假设一个情况,某个按键发出了点击信号,但是该信号不能传递参数,而我们却像知道这是第几次发射该信号的。这可以借助lambda表达式或者偏函数实现。代码如下:
from PyQt5.QtWidgets import QMainWindow, QPushButton, QWidget, \
QMessageBox, QApplication, QHBoxLayout
from functools import partial
import sys
class WinForm(QMainWindow):
def __init__(self, parent=None):
super(WinForm, self).__init__(parent)
button1 = QPushButton('Button 1')
button2 = QPushButton('Button 2')
button1.clicked.connect(lambda: self.onButtonClicked(1)) # lambda方式
button2.clicked.connect(partial(self.onButtonClicked(2))) # 偏函数方式
layout = QHBoxLayout()
layout.addWidget(button1)
layout.addWidget(button2)
main_frame = QWidget()
main_frame.setLayout(layout)
self.setCentralWidget(main_frame)
def onButtonClicked(self, n):
print('Button {0} is pushed'.format(n))
QMessageBox.information(self, "Message box",
'Button {0} is pushed'.format(n))
if __name__ == "__main__":
app = QApplication(sys.argv)
form = WinForm()
form.show()
sys.exit(app.exec_())
装饰器信号与槽
关于装饰器,可以参考这篇笔记。相当于直接可以定义有函数的信号。一般的使用方式如下:
@QtCore.pyqtSlot(参数)
def on_发送者对象名称_发射信号名称(self, 参数):
pass
应用代码实例:
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import QWidget, QApplication, \
QHBoxLayout, QPushButton
from PyQt5 import QtCore
import sys
class CustWidget(QWidget):
def __init__(self, parent=None):
super(CustWidget, self).__init__(parent)
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):
print("Clicked OK Button")
if __name__ == "__main__":
app = QApplication(sys.argv)
win = CustWidget()
win.show()
sys.exit(app.exec_())
每次点击OK按键,控制台都会输出数据。。。
注意一点,QtCore.QMetaObject.connectSlotsByName(self)
这句代码是必须的!!!。这段代码的是PyQt5中信号自动连接到槽函数的核心代码。如果使用装饰器的信号和槽,必须有这一句。
断开连接
使用disconnect
函数即可