信号与槽的参数
上节介绍了信号与槽的基本使用方法,本节介绍其参数传递的情况。通过为槽函数传递特定的参数,可以实现更复杂的功能。既可以传递 Qt 的内置参数,也可以传递自定义参数,当然,内置参数和自定义参数也可以放在一起传递。自定义参数既可以通过 lambda 表达式传递,也可以通过 partial()函数传递。
案例:信号与槽的参数
# -*- coding: utf-8 -*-
'''
【简介】
PySide6中 信号与槽 例子,说明参数传递的使用方法
'''
import sys
from PySide6.QtWidgets import *
from PySide6.QtCore import Signal,slot,QMetaObject
from PySide6.QtGui import *
import time
from functools import partial
class SignalslotDemo(QWidget):
signal1 = Signal()
signal2 = Signal(str)
signal3 = Signal(str,int,list,dict)
signal4 = Signal(str,int,list,dict)
def __init__(self,*args,**kwargs):
super(SignalslotDemo,self).__init__(*args,**kwargs)
self.setWindowTitle('信号与槽案例2-参数传递')
self.resize(400,300)
layout = QVBoxLayout()
self.setLayout(layout)
self.label = QLabel('用来显示信息',self)
layout.addWidget(self.label)
self.button1 = QPushButton("1-内置信号+默认参数",self)
self.button1.setCheckable(True)
layout.addWidget(self.button1)
self.button1.clicked[bool].connect(self.button1Click)
button2 = QPushButton("2-自定义信号+默认参数",self)
button2.setCheckable(True)
self.signal2[str].connect(self.button2Click)
layout.addWidget(button2)
button2.clicked.connect(lambda: self.signal2.emit('我是参数'))
self.button3 = QPushButton("3-内置信号+自定义参数lambda",self)
self.button3.setCheckable(True)
layout.addWidget(self.button3)
self.button3.clicked[bool].connect(lambda bool1: self.button3Click(bool1,button=self.button3,a=5,b='botton3'))
self.button4 = QPushButton("4-内置信号+自定义参数partial",self)
self.button4.setCheckable(True)
layout.addWidget(self.button4)
self.button4.clicked[bool].connect(partial(self.button4Click,*args,button=self.button4,a=7,b='button4'))
self.button5 = QPushButton("5-自定义信号+自定义参数lambda",self)
self.signal3[str,int,list,dict].connect(lambda a1,a2,a3,a4: self.button5Click(a1,a2,a3,a4,button=self.button5,a=7,b='button5'))
layout.addWidget(self.button5)
self.button5.clicked.connect(lambda: self.signal3.emit('参数1',2,[1,2,3,4],{'a': 1,'b': 2}))
self.button6 = QPushButton("6-自定义信号+自定义参数partial",self)
self.signal4[str,int,list,dict].connect(partial(self.button6Click,*args,button=self.button6,a=7,b='button6'))
layout.addWidget(self.button6)
self.button6.clicked.connect(lambda: self.signal4.emit('参数1',2,[1,2,3,4],{'a': 1,'b': 2}))
def button1Click(self,bool1):
if bool1 == True:
self.label.setText("time:%s,触发了'1-内置信号+默认参数',传递一个信号的默认参数:%s',表示该按钮被按下"%(time.strftime('%H:%M:%S'),bool1))
else:
self.label.setText("time:%s,触发了'1-内置信号+默认参数',传递一个信号的默认参数:%s',表示该按钮没有被按下"%(time.strftime('%H:%M:%S'),bool1))
def button2Click(self,_str):
self.label.setText("time:%s,触发了'2-自定义信号+默认参数',传递一个信号的默认参数:%s'"%(time.strftime('%H:%M:%S'),_str))
def button3Click(self,bool1,button,a,b):
if bool1 == True:
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递一个信号的默认参数:{bool1}',表示该按钮被按下。\n三个自定义参数button='{button}',a={a},b='{b}'"
else:
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递一个信号的默认参数:{bool1}',表示该按钮没有被按下。\n三个自定义参数button='{button}',a={a},b='{b}'"
self.label.setText(_str)
def button4Click(self,bool1,button,a,b):
if bool1 == True:
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递一个信号的默认参数:{bool1}',表示该按钮被按下。\n三个自定义参数button='{button}',a={a},b='{b}'"
else:
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递一个信号的默认参数:{bool1}',表示该按钮没有被按下。\n三个自定义参数button='{button}',a={a},b='{b}'"
self.label.setText(_str)
def button5Click(self,*args,button,a,b):
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递信号的默认参数:{args}',\n三个自定义参数button='{button}',a={a},b='{b}'"
# print(args,button,a,b)
self.label.setText(_str)
def button6Click(self,*args,button,a,b):
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递信号的默认参数:{args}',\n三个自定义参数button='{button}',a={a},b='{b}'"
# print(args,button,a,b)
self.label.setText(_str)
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = SignalslotDemo()
demo.show()
app.exec()
内置信号+默认参数
单击按钮1,self.button1 的按状态会切换,self.label会显示信号触发情况
self.button1 = QPushButton("1-内置信号+默认参数",self)
self.button1.setCheckable(True)
layout.addWidget(self.button1)
self.button1.clicked[bool].connect(self.button1Click)
def button1Click(self,bool1):
if bool1 == True:
self.label.setText("time:%s,触发了'1-内置信号+默认参数',传递一个信号的默认参数:%s',表示该按钮被按下"%(time.strftime('%H:%M:%S'),bool1))
else:
self.label.setText("time:%s,触发了'1-内置信号+默认参数',传递一个信号的默认参数:%s',表示该按钮没有被按下"%(time.strftime('%H:%M:%S'),bool1))
自定义信号+默认参数
button2 = QPushButton("2-自定义信号+默认参数",self)
button2.setCheckable(True)
self.signal2[str].connect(self.button2Click)
layout.addWidget(button2)
button2.clicked.connect(lambda: self.signal2.emit('我是参数'))
def button2Click(self,_str):
self.label.setText("time:%s,触发了'2-自定义信号+默认参数',传递一个信号的默认参数:%s'"%(time.strftime('%H:%M:%S'),_str))
内置信号+自定义参数 lambda
在PySide/PyQt编程过程中,经常会遇到为槽函数传递自定义参数的情况,如有一个信号与槽函数的连接如下:
button1.clicked.connect(show_page)
对于 clicked 信号来说,它不能发出参数;对于 show_page()槽函数来说,它需要接收参数,如 show_page()函数可以是这样的:
def show_page(self,name)
print((name,"单击啦")
于是产生一个问题–信号发出的参数个数为0,槽函数接收的参数个数为 1,由于0<1,因此运行之后一定会报错(这是因为信号发出的参数个数必须大于或等于槽函数接收的参数个数)。
本节通过 lambda 表达式来解决这个问题,下面的章节会介绍通过 functools 中的partial()函数来解决这个问题,通常使用lambda 表达式。详见按钮3,代码如下
self.button3 = QPushButton("3-内置信号+自定义参数lambda",self)
self.button3.setCheckable(True)
layout.addWidget(self.button3)
self.button3.clicked[bool].connect(lambda bool1: self.button3Click(bool1,button=self.button3,a=5,b='botton3'))
def button3Click(self,bool1,button,a,b):
if bool1 == True:
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递一个信号的默认参数:{bool1}',表示该按钮被按下。\n三个自定义参数button='{button}',a={a},b='{b}'"
else:
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递一个信号的默认参数:{bool1}',表示该按钮没有被按下。\n三个自定义参数button='{button}',a={a},b='{b}'"
self.label.setText(_str)
如上述代码所示,可以通过lambda 表达式对 button3Click()函数进行封装,这个函数传送4个参数,分别是内置参数 bool1,以及自定义的3 个参数 button、a、b。内置参数表示接钮接下状态,自定义参数传递额外的信息。
内置信号+自定义参数 partial
使用partial()函数的效果和使用lambda表达式的效果是一样的,这里通过*args捕获内置参数bool,代码如下:
from functools import partial
self.button4 = QPushButton("4-内置信号+自定义参数partial",self)
self.button4.setCheckable(True)
layout.addWidget(self.button4)
self.button4.clicked[bool].connect(partial(self.button4Click,*args,button=self.button4,a=7,b='button4'))
def button4Click(self,bool1,button,a,b):
if bool1 == True:
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递一个信号的默认参数:{bool1}',表示该按钮被按下。\n三个自定义参数button='{button}',a={a},b='{b}'"
else:
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递一个信号的默认参数:{bool1}',表示该按钮没有被按下。\n三个自定义参数button='{button}',a={a},b='{b}'"
self.label.setText(_str)
自定义信号+自定义参数 lambda
为了更好地介绍自定义信号的问题,本节定义了比较复杂的信号,即 signal3=Signal(str,int,list,dict),使用它可以传递多个不同类型的参数,使用方法如下:
signal3 = Signal(str,int,list,dict)
def __init__(self,*args,**kwargs):
super(SignalslotDemo,self).__init__(*args,**kwargs)
self.button5 = QPushButton("5-自定义信号+自定义参数lambda",self)
self.signal3[str,int,list,dict].connect(lambda a1,a2,a3,a4: self.button5Click(a1,a2,a3,a4,button=self.button5,a=7,b='button5'))
layout.addWidget(self.button5)
self.button5.clicked.connect(lambda: self.signal3.emit('参数1',2,[1,2,3,4],{'a': 1,'b': 2}))
def button5Click(self,*args,button,a,b):
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递信号的默认参数:{args}',\n三个自定义参数button='{button}',a={a},b='{b}'"
# print(args,button,a,b)
self.label.setText(_str)
从上面的代码中可以看出,其使用方法和单一参数的使用方法没有什么不同。
自定义信号+自定义参数 partiall
使用 partial0函数传递多个参数和单个参数没有什么不同,这一点和 lambda 表达式样。partial()函数可以使用*args 捕自定义信号的参数,代码如下:
signal4 = Signal(str,int,list,dict)
def __init__(self,*args,**kwargs):
super(SignalslotDemo,self).__init__(*args,**kwargs)
self.button6 = QPushButton("6-自定义信号+自定义参数partial",self)
self.signal4[str,int,list,dict].connect(partial(self.button6Click,*args,button=self.button6,a=7,b='button6'))
layout.addWidget(self.button6)
self.button6.clicked.connect(lambda: self.signal4.emit('参数1',2,[1,2,3,4],{'a': 1,'b': 2}))
def button6Click(self,*args,button,a,b):
_str = f"time:{time.strftime('%H:%M:%S')},触发了'{button.text()}',传递信号的默认参数:{args}',\n三个自定义参数button='{button}',a={a},b='{b}'"
# print(args,button,a,b)
self.label.setText(_str)