PyQt中信号与槽概念定义如下(网络上引用的):
信号(signal)和槽(slot)是Qt的核心机制,也是在PyQt编程中对象之间进行通信的机制。在创建事件循环之后,通过建立信号和槽的连接就可以实现对象之间的通信。当信号发射(emit)时,连接的槽函数将会自动执行。
所谓内置信号与槽的使用。是指在发射信号时,使用窗口控件的函数,而不是自定义的函数。信号与槽的连接方法是通过QObject.signal.connect将一个QObject的信号连接到另一个QObject的槽函数。
信号与槽有三种使用方法,第一种是内置信号与槽的使用,第二种是自定义信号与槽的使用,第三种是装饰器的信号与槽的使用。
python 装饰器详解
【Python】*args
和 **kwargs
的用法【最全详解】
官方网站:PyQt API中信号与槽详细解释
内置信号与槽的使用
参考文章:Python Qt GUI设计:信号与槽的使用方法(基础篇—7)
Qt Designer中提供了一些最基础的信号和槽设置方法,在实际的项目开发中,信号和槽最佳的使用方式是Qt Designer和编程相结合,才能提高开发效率。
生成python代码,
自定义信号与槽的使用
不适用内置信号与槽,而使用自定义信号与槽。自定义信号与槽是指在发射信号时,不使用窗口控件的函数,而是使用自定义的函数(简单地说,就是使用pyqtSignal类实例发射信号)。
使用方法示例如下:
PyQt5自定义信号与槽带示例讲解
关键代码:
设置信号事件:signal_single_link = pyqtSignal(str,str,str) #定义下载单条链接的信号参数(文件名,文件大小,文件进度)
定义槽函数:
def showSingalInfo(self,file_name,file_size,file_progress):self.label_txt_path.setText('文件名:'+file_name+'文件大小:'+file_size+'文件进度:'+file_progress)
使用connect()函数,绑定槽函数:self.signal_single_link.connect(self.showSingalInfo)
发送信号给槽,使用emit()函数:self.signal_single_link.emit(str(name),str(file_size),str(formatFloat§))
上述自定义信号与绑定槽操作的作用是下载过程中(单开一个线程实现下载过程),传进度返回给主线程(UI主界面是主线程)中的label控件显示
使用装饰器pyqtSlot定义信号与槽
官方网站:PyQt API中信号与槽详细解释
@pyqtSlot()有两种使用情况。文章:PyQt5 随笔:信号与槽的两种使用方法:@pyqtSlot() 和 connect()
@pyqtSlot()是这种方式的修饰关键词,他表明下面函数是信号槽函数
一个控件同时要写多个信号与槽函数时,只需要写一遍@pyqtSlot()关键词,中间可以有其他函数隔开。
引用自文章:PyQt 5信号与槽的几种高级玩法
PyQt5 连接信号与自定义槽函数,解决槽函数重复执行的问题
Qt for Python 信号和槽的使用详解,比较好理解使用装饰器生成信号事件的文章,但文章是使用PySide2来写 Qt 程序。
有的读者可能注意到,我们一直没有解释下面这行代码的含义:
QMetaObject.connectSlotsByName(QObject)
事实上,它是在PyQt 5中根据信号名称自动连接到槽函数的核心代码。通过前面章节中的例子可以知道,使用pyuic5命令生成的代码中会带有这么一行代码,接下来对其进行解释。
这行代码用来将QObject中的子孙对象的某些信号按照其objectName连接到相应的槽函数。这句话读起来有些拗口,这里举个例子进行简单说明。以上面例子中的代码为例:
假设代码QtCore.QMetaObject.connectSlotsByName(self)已经执行,则下面的代码:
@QtCore.pyqtSlot()
def on_okButton_clicked(self):print( "单击了OK按钮")
会被自动识别为下面的代码(注意,函数中去掉了on,因为on会受到connectSlotsByName的影响,加上on运行时会出现问题):
def __init__(self, parent=None):self.okButton.clicked.connect(self.okButton_clicked)
def okButton_clicked(self):print("单击了OK按钮")
信号与槽的断开与连接
使用disconnect()函数可以解除信号与槽函数的绑定。
from PyQt5.QtCore import QObject , pyqtSignalclass SignalClass(QObject):# 声明无参数的信号signal1 = pyqtSignal()# 声明带一个int类型参数的信号signal2 = pyqtSignal(int)def __init__(self,parent=None):super(SignalClass,self).__init__(parent)# 将信号signal1连接到sin1Call和sin2Call这两个槽函数self.signal1.connect(self.sin1Call)self.signal1.connect(self.sin2Call)# 将信号signal2连接到信号signal1self.signal2.connect(self.signal1)# 发射信号self.signal1.emit()self.signal2.emit(1)# 断开signal1、signal2信号与各槽函数的连接self.signal1.disconnect(self.sin1Call)self.signal1.disconnect(self.sin2Call)self.signal2.disconnect(self.signal1)# 将信号signal1和signal2连接到同一个槽函数sin1Callself.signal1.connect(self.sin1Call)self.signal2.connect(self.sin1Call)# 再次发射信号self.signal1.emit()self.signal2.emit(1)def sin1Call(self):print("signal-1 emit")def sin2Call(self):print("signal-2 emit")if __name__ == '__main__': signal = SignalClass()
运用自定义信号与槽方法的实际场景
运用自定义信号与槽方法的实际场景:信号和槽一般用于多个窗口之间传递信息, 或者前后端传递信息。
参考文章:大爽pyqt5笔记&教程 三 信号和槽 Signals & Slots 实现窗口跳转、返回、恢复、传参
使用lambda或者functools中的partial函数实现自定义参数的传递
python 中的functools.partial 使用方法
参考文章:python GUI库图形界面开发之PyQt5信号与槽的高级使用技巧(自定义信号与槽)详解与实例
import sys
from PyQt5.QtWidgets import *
from functools import partial
class WinForm(QMainWindow):def __init__(self,parent=None):super(WinForm, self).__init__(parent)#实例化两个按钮button1=QPushButton('Button1')button2=QPushButton('Button2')#todo 第一种方法#单击信号关联槽函数,利用Lanbda表达式传递一个参数# button1.clicked.connect(lambda :self.onButtonClick(1))# button2.clicked.connect(lambda :self.onButtonClick(2))##todo 第二种方法button1.clicked.connect(partial(self.onButtonClick, 1))button2.clicked.connect(partial(self.onButtonClick, 2))#实例化窗口main=QWidget()#设置窗口的布局,并向其中添加控件layout=QHBoxLayout(main)layout.addWidget(button1)layout.addWidget(button2)#设置为中央控件self.setCentralWidget(main)def onButtonClick( self,n ):#弹窗信息提示框,输出被点击的信息print("Button {0}".format(n))QMessageBox.information(self,'信息提示框','Button {0}'.format(n))
if __name__ == '__main__':app=QApplication(sys.argv)form=WinForm()form.show()sys.exit(app.exec_())
代码分析
重点解释
使用lambda表达式传递按钮数字给槽函数,当然还可以传递其他东西,甚至是按钮本身
button1.clicked.connect(lambda :self.onButtonClick(1))
button2.clicked.connect(lambda :self.onButtonClick(2))
另一种方法是使用functools中的partial函数
button1.clicked.connect(partial(self.onButtonClick, 1))
button2.clicked.connect(partial(self.onButtonClick, 2))