PyQt5快速入门(二)PyQt5信号槽机制

一、信号槽机制简介

1、信号槽简介

信号槽是Qt的核心机制,也是PyQt编程中对象进行通信的机制。在Qt中,QObject对象和PyQt中所有继承自QWidget的控件都支持信号槽机制。当信号发射时,连接的槽函数会自动执行。在PyQt5中,信号与槽函数通过object.signal.connect()方法进行连接。

信号槽特点如下:

(1)一个信号可以连接多个槽

(2)一个信号可以连接另一个信号

(3)信号参数可以是任意Python类型

(4)一个槽可以监听多个信号

(5)信号与槽的连接方式可以是同步连接,也可以是异步连接。

(6)信号与槽的连接可以跨线程

(7)信号可以断开

在编写一个类时,要首先定义的类的信号与槽,在类中信号与槽进行连接,实现对象之间的数据传输。当事件或状态发生变化时,会发出信号,进而触发执行事件或信号关联的槽函数。信号槽机制示意如下:

2、定义信号

PyQt的内置信号是自动定义的,使用PyQt5.QtCore.pyqtSignal函数可以为QObject对象创建一个信号,使用pyqtSignal函数可以把信号定义为类的属性。

class pyqtSignal:

def __init__(self, *types, name: str = ...) -> None: ...

types参数表示定义信号时参数的类型,name参数表示信号的名称,默认使用类的属性名称。

使用pyqtSignal函数创建一个或多个重载的未绑定的信号作为类的属性,信号只能在QObject的子类中定义。信号必须在类创建时定义,不能在类创建后作为类的属性动态添加进来。使用pyqtSignal函数定义信号时,信号可以传递多各参数,并指定信号传递参数的类型,参数类型是标准的Python数据类型,包括字符串、日期、布尔类型、数字、列表、字典、元组。

from PyQt5.QtCore import pyqtSignal, QObject

class StandardItem(QObject):

# 定义信号,信号有两个参数,两个参数的类型分别为str,str,信号名称为dataChanged

data_changed = pyqtSignal(str, str, name="dataChanged")

# 更新信息,发送信号

def update(self):

self.dataChanged.emit("old status", "new status")

3、操作信号

使用connect函数可以将信号绑定到槽函数上,使用disconnect函数可以解除信号与槽函数的绑定,使用emit函数可以发射信号。

QObject.signal.connect(self, slot, type=None, no_receiver_check=False)

建立信号到槽函数的连接,type为连接类型。

QObject.signal.disconnect(self, slot=None)

断开信号到槽的连接

emit(self, *args)

发送信号,args为可变参数。

import sys

from PyQt5.QtCore import pyqtSignal, QObject, QCoreApplication

class StandardItem(QObject):

# 定义信号,信号有两个参数,两个参数的类型分别为str,str,信号名称为dataChanged

data_changed = pyqtSignal(str, str, name="dataChanged")

# 更新信息,发送信号

def update(self):

self.dataChanged.emit("old status", "new status")

# 定义槽函数

def onDataChanged(self, old, new):

print(old)

print(new)

if __name__ == "__main__":

app = QCoreApplication(sys.argv)

item = StandardItem()

item.dataChanged.connect(item.onDataChanged)

item.update()

sys.exit(app.exec_())

# OUTPUT:

# old status

# new status

二、信号与槽应用

1、内置信号与槽函数

内置信号是QObject对象自动定义的信号,内置槽函数是QObject对象自动定义的槽函数,可以通过QObject.signal.connect函数将QObject对象的内置信号连接到QObject对象的槽函数。

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

import sys

from PyQt5.QtWidgets import QWidget, QApplication, QPushButton

class MainWindow(QWidget):

def __init__(self, parent=None):

super().__init__(parent)

self.setWindowTitle("MainWindow Demo")

self.resize(800, 600)

button = QPushButton("close", self)

# 连接内置信号与自定义槽

button.clicked.connect(self.onClose)

# 自定义槽函数

def onClose(self):

self.close()

if __name__ == "__main__":

app = QApplication(sys.argv)

window = MainWindow()

window.show()

sys.exit(app.exec_())

点击按钮时触发按钮内置的clicked信号,执行绑定的自定义槽函数onClose。

3、自定义信号与内置槽函数

import sys

from PyQt5.QtCore import pyqtSignal

from PyQt5.QtWidgets import QWidget, QApplication, QPushButton

class MainWindow(QWidget):

closeSignal = pyqtSignal()

def __init__(self, parent=None):

super().__init__(parent)

self.setWindowTitle("MainWindow Demo")

self.resize(800, 600)

button = QPushButton("close", self)

# 连接内置信号与自定义槽

button.clicked.connect(self.onClose)

# 连接自定义信号closeSignal与内置槽函数close

self.closeSignal.connect(self.close)

# 自定义槽函数

def onClose(self):

# 发送自定义信号

self.closeSignal.emit()

if __name__ == "__main__":

app = QApplication(sys.argv)

window = MainWindow()

window.show()

sys.exit(app.exec_())

通过连接内置信号clicked到自定义槽函数onClose,在自定义槽函数onClose内发送自定义信号closeSignal,并将自定义信号closeSignal与内置槽函数close连接。

4、自定义信号与自定义槽函数

import sys

from PyQt5.QtCore import pyqtSignal

from PyQt5.QtWidgets import QWidget, QApplication, QPushButton

class MainWindow(QWidget):

closeSignal = pyqtSignal()

def __init__(self, parent=None):

super().__init__(parent)

self.setWindowTitle("MainWindow Demo")

self.resize(800, 600)

button = QPushButton("close", self)

# 连接内置信号与自定义槽

button.clicked.connect(self.onClicked)

# 连接自定义信号closeSignal与内置槽函数close

self.closeSignal.connect(self.onClose)

# 自定义槽函数

def onClicked(self):

# 发送自定义信号

self.closeSignal.emit()

# 自定义槽函数

def onClose(self):

self.close()

if __name__ == "__main__":

app = QApplication(sys.argv)

window = MainWindow()

window.show()

sys.exit(app.exec_())

三、信号槽应用进阶

1、自定义信号槽

通常通过类变量定义信号对象,在__init__函数前定义自定义信号。

class TestObject(QObject):

# 定义无参的信号

noParametersSignal = pyqtSignal()

# 定义一个参数的信号,参数类型为int

oneParameterSignal = pyqtSignal(int)

# 定义一个参数的重载版本的信号,参数类型可以为int或str

oneParameterOverloadSignal = pyqtSignal([int], [str])

# 定义两个参数的重载版本的信号,参数类型为int,str或int,int

twoParametersOverloadSignal = pyqtSignal([int, str], [int, int])

# 定义一个list参数类型的信号

oneParameterSignalList = pyqtSignal(list)

# 定义一个dict参数类型的信号

oneParameterSignalDict = pyqtSignal(dict)

类的槽函数定义与类的普通方法定义相同。

class TestObject(QObject):

# 定义无参的信号

noParametersSignal = pyqtSignal()

# 定义一个参数的信号,参数类型为int

oneParameterSignal = pyqtSignal(int)

# 定义一个参数的重载版本的信号,参数类型可以为int或str

oneParameterOverloadSignal = pyqtSignal([int], [str])

# 定义两个参数的重载版本的信号,参数类型为int,str或int,int

twoParametersOverloadSignal = pyqtSignal([int, str], [int, int])

# 定义无参的槽函数

def onNoParameterSlot(self):

pass

# 定义一个参数的槽函数,参数为整型nIndex

def onOneParameterSlot(self, nIndex):

pass

# 定义两个参数的槽函数,参数为整型nIndex,字符串型sStatus

def onTwoParametersSlot(self, nIndex, sStatus):

pass

通过connect方法连接信号与槽函数,信号与槽函数可以属于同一个QObject对象,也可以是不同的QObject对象。

test = TestObject()

test.noParametersSignal.connect(test.onNoParameterSlot)

test.oneParameterSignal.connect(test.onOneParameterSlot)

test.twoParametersOverloadSignal.connect(test.onTwoParametersSlot)

信号的发送通过emit方法进行发送。

def update(self):

self.noParametersSignal.emit()

self.oneParameterSignal.emit(100)

self.oneParameterOverloadSignal("Hello, PyQt5")

self.twoParametersOverloadSignal(100, "Hello, PyQt5")

2、信号槽传递自定义参数

Qt中信号发出的参数个数必须大于等于槽函数的参数个数,PyQt使用自定义参数传递解决槽函数参数比信号参数多的问题。使用Lambda表达式或functools的partial函数可以传递自定义参数给槽函数,自定义参数类型可以是Python任意类型。

import sys

from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QHBoxLayout

from functools import partial

class MainWindow(QWidget):

def __init__(self, parent=None):

super().__init__(parent)

button1 = QPushButton("Button1", self)

button2 = QPushButton("Button2", self)

layout = QHBoxLayout()

layout.addWidget(button1)

layout.addWidget(button2)

self.setLayout(layout)

self.setWindowTitle("MainWindow Demo")

self.resize(800, 600)

# lambda

button1.clicked.connect(lambda: self.onButtonClicked(1))

button2.clicked.connect(lambda: self.onButtonClicked(2))

# partial

button1.clicked.connect(partial(self.onButtonClicked, 1))

button2.clicked.connect(partial(self.onButtonClicked, 2))

# 自定义槽函数

def onButtonClicked(self, n):

print("Button {0} is Clicked".format(n))

if __name__ == "__main__":

app = QApplication(sys.argv)

window = MainWindow()

window.show()

sys.exit(app.exec_())

3、信号槽与装饰器

PyQt中可以通过Python装饰器定义信号与槽函数,使用方法如下:

@PyQt5.QtCore.pyqtSlot(bool)

def on_发送者对象名称_发射信号名称(self, parameter):

pass

发送者对象名称是使用setObjectName为QObject对象设置的对象名称,通过信号名称连接到槽函数的connectSlotsByName函数如下:

QtCore.QMetaObject.connectSlotsByName(self, QObject)

connectSlotsByName用于将QObject子孙对象的某些信号根据名称连接到某些QObject对象的相应槽函数。

import sys

from PyQt5 import QtCore

from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QHBoxLayout

class MainWindow(QWidget):

def __init__(self, parent=None):

super().__init__(parent)

button1 = QPushButton("Button1", self)

button1.setObjectName("Button1")

button2 = QPushButton("Button2", self)

button2.setObjectName("Button2")

layout = QHBoxLayout()

layout.addWidget(button1)

layout.addWidget(button2)

self.setLayout(layout)

self.setWindowTitle("MainWindow Demo")

self.resize(800, 600)

QtCore.QMetaObject.connectSlotsByName(self)

@QtCore.pyqtSlot()

def on_Button1_clicked(self):

print("Button1 is clicked")

@QtCore.pyqtSlot()

def on_Button2_clicked(self):

print("Button2 is clicked")

if __name__ == "__main__":

app = QApplication(sys.argv)

window = MainWindow()

window.show()

sys.exit(app.exec_())

四、事件处理机制

1、事件机制与信号槽机制的区别

PyQt为事件处理提供了高级别的信号槽机制和低级别的事件处理机制,信号槽机制是事件处理机制的高级封装。使用控件时,不用考虑事件处理机制,只需要关心信号槽即可;对于自定义派生控件,必须考虑事件处理机制,根据控件的行为需求重新实现相应的事件处理函数。

2、事件处理的方法

PyQt提供了5种事件处理和过滤方法,分别为:

(1)重新实现事件处理函数

常用的事件处理函数如paintEvent、mouseMoveEvent、mousePressEvent、mouseReleaseEvent等。

(2)重新实现QObject.event事件分发函数

在增加新的事件时,需要重新实现QObject.event方法,并增加新事件的分发路由。

(3)安装事件过滤器

如果对QObject对象调用installEventFilter方法,则为QObject对象安装事件过滤器。QObject对象的所有事件都会先传递到事件过滤器eventFilter函数,在事件过滤器eventFilter函数中可以丢弃或修改某些事件,对感兴趣的事件使用自定义的事件处理机制,对其它事件使用默认事件处理机制。事件过滤机制会对QObject的所有事件进行过滤,因此如果要过滤的事件比较多则会影响程序性能。

(4)在QApplication安装事件过滤器

在QApplication对象安装事件过滤器将会对所有QObject对象的所有事件进行过滤,并且会首先获得事件,即将事件发送给其它任何一个事件过滤器前,都会首先发送给QApplication的事件过滤器。

(5)重新QApplication的notify方法

PyQt使用QApplication对象的notify方法进行分发事件,要想在任何事件过滤器前捕获事件唯一的方法就是重新实现QApplication的notify方法。

3、事件处理实例

QDialog对话框在ESC按键按下时会自动退出,使用事件处理和过滤对按下ESC按键进行处理。

(1)重新实现事件处理函数

import sys

from PyQt5.QtWidgets import QDialog, QApplication

from PyQt5.QtCore import Qt

class Dialog(QDialog):

def __init__(self, parent=None):

super().__init__(parent)

# 重新实现keyPressEvent

def keyPressEvent(self, event):

if event.key() != Qt.Key_Escape:

QDialog.keyPressEvent(self, event)

if __name__ == "__main__":

app = QApplication(sys.argv)

dialog = Dialog()

dialog.exec_()

sys.exit(app.exec_())

(2)重新实现event函数

import sys

from PyQt5.QtWidgets import QDialog, QApplication

from PyQt5.QtCore import Qt

from PyQt5.QtGui import QKeyEvent

class Dialog(QDialog):

def __init__(self, parent=None):

super().__init__(parent)

# 重新实现keyPressEvent

def event(self, event):

if event.type() == QKeyEvent.KeyPress and event.key() == Qt.Key_Escape:

return True

else:

return QDialog.event(self, event)

if __name__ == "__main__":

app = QApplication(sys.argv)

dialog = Dialog()

dialog.exec_()

sys.exit(app.exec_())

(3)QObject安装事件过滤器

import sys

from PyQt5.QtWidgets import QDialog, QApplication

from PyQt5.QtCore import Qt

from PyQt5.QtGui import QKeyEvent

class Dialog(QDialog):

def __init__(self, parent=None):

super().__init__(parent)

self.installEventFilter(self)

def eventFilter(self, watched, event):

if event.type() == QKeyEvent.KeyPress and event.key() == Qt.Key_Escape:

return True

else:

return QDialog.eventFilter(self, watched, event)

if __name__ == "__main__":

app = QApplication(sys.argv)

dialog = Dialog()

dialog.exec_()

sys.exit(app.exec_())

(4)QApplication安装事件过滤器

import sys

from PyQt5.QtWidgets import QDialog, QApplication

from PyQt5.QtCore import Qt

from PyQt5.QtGui import QKeyEvent

class Dialog(QDialog):

def __init__(self, parent=None):

super().__init__(parent)

def eventFilter(self, watched, event):

if event.type() == QKeyEvent.KeyPress and event.key() == Qt.Key_Escape:

return True

else:

return QDialog.eventFilter(self, watched, event)

if __name__ == "__main__":

app = QApplication(sys.argv)

dialog = Dialog()

app.installEventFilter(dialog)

dialog.exec_()

sys.exit(app.exec_())

pyqt 槽任意参数_PyQt5快速入门(二)PyQt5信号槽机制相关推荐

  1. Qt计算器开发(二):信号槽实现数学表达式合法性检查

    表达式的合法性 由于我们的计算器不是单步计算的,所以我们能够一次性输入一个长表达式.然而假设用户输入的长表达式不合法的话,那么就会引发灾难.所以有必要对于用户的输入做一个限制. 一些限制举例: 比方, ...

  2. pyqt5菜鸟教程_[ PyQt入门教程 ] PyQt5信号与槽

    信号和槽是PyQt编程对象之间进行通信的机制.每个继承自QWideget的控件都支持信号与槽机制.信号发射时(发送请求),连接的槽函数就会自动执行(针对请求进行处理).本文主要讲述信号和槽最基本.最经 ...

  3. python qt快速入门_PyQt5快速入门(一)

    PyQt5快速入门(一) 前言 为什么选择PyQt5作为GUI框架? API与Qt一致, 学会PyQt后再使用qt很简单 开发迅速, 可视化操作,使用designer快速拖拽布局进行调试 可以将文件打 ...

  4. Qt-VS开发:解决VS中使用带有信号槽的导出对象库时,信号槽不工作的问题

    解决办法 需要把导出库的头文件加入到调用此动态库的项目中,只加入到搜索目录中是不行的. 加入到项目中后,VS会自动生成moc_xxx.cpp文件,可以在GeneratedFiles/Debug或Gen ...

  5. pyqt 槽任意参数_PyQt5信号与槽机制入门(一)

    信号(Signal)与槽(Slot)是Qt中的核心机制,也是在PyQt编程中对象之间进行通信的机制.当事件或者状态发生改变时,就会发出信号,信号会触发所有与这个事件(信号)相关的函数(槽):一个信号可 ...

  6. Vue 基础快速入门(二)

    Vue 组件化编程 模块, 组件, 模块化与组件化 模块 理解:向外提供特定功能的 js 程序, 一般就是一个 js 文件 为什么:js 文件很多很复杂 作用:复用 js,简化 js 的编写, 提高 ...

  7. ElasticSearch快速入门二(Restful介绍)

    本节课从三个方便讲解 什么是restful ? API: Application Programming Interface的缩写,中文意思就是应用程序接口. ●XML: . 可扩展标记语言,是一种程 ...

  8. jquery 快速入门二

    ---恢复内容开始--- 操作标签 样式操作 样式类 addClass();//添加指定的CSS类名. removeClass();//移除指定的类名. hasClass();//判断样式不存在 to ...

  9. Webpack5快速入门 (二) CSS相关loader的使用及兼容性处理 手把手带你打开前端工程化的大门

    目录 一.CSS-Loader

最新文章

  1. 【端口号和服务漫谈】
  2. Apache POI和EasyExcel 第六集:Apache POI的Excel读取单元格中的计算公式
  3. C#中RichTextBox文本居中显示
  4. 使用Tornado实现Ajax请求
  5. Oracle ODP.NET数据库访问连接字符串
  6. 6个好用的Web开发工具
  7. 嵌入式电路设计(第一个商业pcb电路图绘制)
  8. ★LeetCode(202)——快乐数(JavaScript)
  9. session的removeAttribute()和invalidate()的区别
  10. 实战丨基于接口的银行系统自动化测试实践
  11. 这就是Machine Learning
  12. json.loads解码字符串时出错:JSONDecodeError: Invalid \escape: line 1 column 2687 (char 2686)
  13. 关于C#中的get与set函数
  14. Embedded ProC(嵌入式ProC)与Tuxedo中间件
  15. X265代码学习1-X265源码下载编译及VS调试配置
  16. 人与人,人与自然。文/江湖一剑客
  17. 王巧乐菇凉的360图书馆--记录大量web日志分析的内容,非常好
  18. openoffic需要的jar包
  19. CF868F 分治优化dp
  20. Cantor(有理数)

热门文章

  1. 关于动态创建控件性能提高 以及 SuspendLayout ResumeLayout 的使用
  2. uva 815之理解诡异的海平线题目之不容易
  3. Linux 软件安装与卸载之获取程序包的途径
  4. NGUI: UIPanel控件
  5. 创建ACFS集群文件系统(命令方式)
  6. 返回空的List集合
  7. 沉默是金不如开口为银
  8. F5 CMP architecture
  9. 【事故反演】配置过程(变位)
  10. 2019秋季PAT甲级_C++题解