PySide6/PyQT多线程之 信号与槽 / (Signal Slot)的高效利用

在这里插入图片描述

前言

PySide6/PyQT信号槽是一种事件处理方式,允许程序中的对象发送和接收信号。

PySide6/PyQT 精进的过程中,一定躲不开 信号和槽 这座大山,这是一个比较有意思的知识点:

  • 初接触的看不懂,觉得复杂;
  • 看得懂的又觉得简单。

简单和难另说,将 PySide6/PyQT信号和槽 讲的清楚,这个才是重点。




其实也挺简单,分三步走:

  1. 定义信号Signal
  2. 定义槽Slot
  3. 将信号和槽连接:Signal().connect.Slot()

本文给你捋清楚它的具体使用,让你轻松掌握这一知识点,跨过这座大山。


知识点📖📖

本文用到的几个PySide6的知识点及链接。

作用链接
创建新线程QThread
对象间通信的机制,允许对象发送和接收信号Signal
用于响应Signal信号的方法Slot

基础概念

PySide6/PyQT 中的信号和槽是一种对象间通信机制。

信号(Signal)槽(Slot)
事件的发射者对事件的响应
在对象中定义的方法,在特定事件发生时被触发响应信号的函数,在信号发生时被调用

理解 信号和槽

用通俗易懂的话解释 PySide6/PyQT的信号和槽:

PySide6/PyQT信号和槽 机制简单地理解为一种 订阅机制

  • 信号充当了 发布者publisher)的角色,负责发布消息;
  • 槽扮演了 订阅者subscriber)的角色,用于接收消息并作出响应。
  • 槽可以订阅一个或多个信号,当信号发生时,槽会自动被调用执行。

信号 Signal

PySide6/PyQT中,可以使用 Signal 来定义信号。

信号 是一种特殊函数,可以在特定的情况下被 QObject 对象 发射(emit)

  • 下面代码定义了一个名为 my_signal 的信号,它接受一个整形参数(可以为空,也可以更换为其它类型
from PySide6.QtCore import (QThread, Signal)


class MyThread(QThread):
    my_signal = Signal(int)

槽 Slot

PySide6/PyQT中,可以使用 @Slot()装饰器 来定义

是普通的函数,它可以被信号调用。当一个信号被发射时,与之相连接的槽将被调用,并将信号的参数传递给槽。

  • 下面定义了一个名为 my_slot 的槽,它接受一个字符串参数,并打印接收到的数据
from PySide6.QtCore import (QThread, Slot)


class MyThread(QThread):
    
    @Slot(int)
    def my_slot(self, data):
        print("Received data: ", data)

值得注意是:

  • 这里的 Slot(int) 可以不写,但是写了可以提高代码可读性和执行效率。
  • 首先,标明这是一个槽函数;
  • 其次,在运行时动态地连接信号,在一定程度上提高代码的执行效率,因为在编译期间不需要生成额外的代码来连接信号和槽。

连接信号和槽

PySide6/PyQT 中,可以使用 connect() 方法将信号和槽相连接,如下所示:

  • 下面代码将sender对象的my_signal信号receiver对象的my_slot槽相连接。
  • sender对象发射my_signal信号时,receiver对象的my_slot槽将被调用。
sender = MyThread()
receiver = MyThread()

sender.my_signal.connect(receiver)

其实就是 使用 connect 将两者连接起来;


注意事项

重要的事情要强调三遍!



信号和槽只能在 QObject的子类里使用!!!

信号和槽只能在 QObject的子类里使用!!!

信号和槽只能在 QObject的子类里使用!!!


然而,在PySide6/PyQT 中,大部分常用的类都是继承了QObject类的,所以这个问题倒无需担心,只需知道有这一概念即可。


信号和槽必须是相同的参数类型。在定义信号和槽时,必须确保它们的参数类型和个数是相同的,否则无法正确连接和触发信号和槽。

信号和槽必须是相同的参数类型。在定义信号和槽时,必须确保它们的参数类型和个数是相同的,否则无法正确连接和触发信号和槽。

信号和槽必须是相同的参数类型。在定义信号和槽时,必须确保它们的参数类型和个数是相同的,否则无法正确连接和触发信号和槽。



常见异常

如果在非 QObject 的子类中使用 SignalSlot会遇到一些异常情况。这是因为在非 QObject 的子类中没有定义 Signalslot,也没有 QObject 提供的信号和槽管理机制。

在非 QObject 的子类中使用 SignalSlot,会遇到以下异常情况:

  • 定义 Signal 时会出现 NameError,因为 Signal是在 QObject 中定义的;
  • connect() 时会出现 AttributeError,因为 connect()QObject 的成员函数;
  • 在 信号emit() 时会出现 AttributeError,即属性错误,因为该类中没有该函数。

信号和槽 的基本使用

说完了 基础概念,现在上代码来检验学习成果了。

代码

# -*- coding: utf-8 -*-

import time


from PySide6.QtCore import (QThread, Signal, Slot, QSize)
from PySide6.QtWidgets import (QApplication, QPushButton, QLabel, QVBoxLayout, QWidget)


class MyThread(QThread):
    my_signal = Signal(int)
    finished_signal = Signal()

    def __init__(self, count):
        super().__init__()
        self.count: int = count

    def run(self):
        for idx in range(1, self.count + 1):
            time.sleep(1)
            # 任务进行时发出信号
            self.my_signal.emit(idx)
	    # 任务完成后发出信号
        self.finished_signal.emit()


class MainWindow(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.setup_ui()
        #
        self.button.clicked.connect(self.setup_thread)

    def setup_ui(self):
        self.setWindowTitle('demo')
        self.resize(QSize(250, 180))
        # 创建一个垂直布局
        layout = QVBoxLayout()
        # 创建一个标签
        self.label = QLabel('This is a label => ')
        layout.addWidget(self.label)
        # 创建一个按钮
        self.button = QPushButton('Send Request')
        layout.addWidget(self.button)
        # 将布局设置为主窗口的布局
        self.setLayout(layout)
        # 显示窗口
        self.show()

    def setup_thread(self):
        self.thread_ = MyThread(count=5)
        self.thread_.my_signal.connect(self.thread_progress)
        self.thread_.finished_signal.connect(self.thread_finished)
        self.thread_.start()

    @Slot(int)
    def thread_progress(self, item):
        self.label.setText('This is a label => ' + str(item))

    @Slot()
    def thread_finished(self):
        self.label.setText('This is a label finished.')


if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

MyThread

  • 继承了 QObject,创建了一个名为 MyThreadQThread 类;
  • 包含一个名为my_signalfinished_signal 的信号,它们分别在 任何进行时任务完成后 发射;
  • 注意 my_signal 是带参数的,而 finished_signal 不带参数,这个需要与 槽函数对应!!!
  • 循环执行 count 次数的操作,每次 通过 my_signal 发射,从而修改 应用程序中的 lable
  • 当循环完成后,通过 finished_signal 发射信号,修改 应用程序中的 label

MainWindow

  • 继承了 QWidget,实现了包含一个按钮和一个标签的简单窗口;
  • setup_thread 函数中,实例化了MyThread,并将实例化后的 my_signal 和 finished_signal 信号连接到 thread_progress 和 thread_finished 函数;
  • thread_progress 和 thread_finished为槽函数,当my_signal 和 finished_signal发出信号时,对应Slot(槽函数)将被调用,并修改label 的显示。

运行效果

在这里插入图片描述

后话

本次分享到此结束,
see you~🐱‍🏍🐱‍🏍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/15834.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

本地 WAF 已死,云 WAF 永生

多年来,Web 应用程序防火墙 (WAF) 一直是应用程序保护的代名词。事实上,许多应用程序安全团队认为保护其应用程序的最佳选择是一流的本地 WAF 解决方案,尤其是当这些应用程序部署在本地或私有云中时。 但自从引入本地 WAF 以来,…

JMeter的使用(二)

九、直连数据库 通过直连数据库让程序代替接口访问数据库,如果二者预期结果不一致,就找到了程序缺陷。 获取某条学院的名字,放在百度搜索: JMeter 不具备直连数据库功能,必须整合第三方(jar包)实现配置数据库的连接通过JDBC Re…

@PostConstruct注解和@PreDestroy注解

前言 Bean注解指定初始化和销毁的方法,也介绍了使用InitializingBean和DisposableBean来处理bean的初始化和销毁。JDK中还提供了两个注解能够在bean创建完成并且属性赋值完成之后执行一些初始化工作和在容器销毁bean之前通知我们进行一些清理工作。 1.PostConstru…

LDAP概念和原理介绍

LDAP概念和原理介绍 相信对于许多的朋友来说,可能听说过LDAP,但是实际中对LDAP的了解和具体的原理可能还比较模糊,今天就从“什么是LDAP”、“LDAP的主要产品”、“LDAP的基本模型”、“LDAP的使用案例”四个方面来做一个介绍。 我们在开始…

有什么牌子台灯性价比高?性价比最高的护眼台灯

由心感叹现在的孩子真不容易,学习压力比我们小时候大太多,特别是数学,不再是简单的计算,而更多的是培养学生其他思维方式,有时候我都觉得一年级数学题是不是超纲了。我女儿现在基本上都是晚上9点30左右上床睡觉&#x…

自动拣货仓库亮灯方案

方案目标概叙: 系统在美团平台下单后,骑手会收到取货码,凭借取货码到指定的智能仓库去取货,仓库标签系统调取相应订单信息,执行亮灯指令(屏幕显示订单信息及拣货数量,并亮灯)&#…

【MySQL】存放页面的大池子——InnoDB的表空间

概念: 页: 是InnoDB存储引擎管理数据库的最小磁盘单位,一个页的大小一般是16KB。一次至少读取一页的数据到内存,或者刷新一页的数据到磁盘。数据页:FIL_PAGE_INDEX类型的页,B树中的节点就是数据页。区&…

Elasticsearch --- 索引库、文档操作

一、索引库操作 索引库就类似数据库表,mapping映射就类似表的结构。 我们要向es中存储数据,必须先创建“库”和“表”。 1.1、mapping映射属性 mapping是对索引库中文档的约束,常见的mapping属性包括: type:字段数据…

标准ACL配置

标准ACL配置 【实验目的】 掌握标准ACL的配置。 验证配置。 【实验拓扑】 实验拓扑如图1所示。 图1 实验拓扑 设备参数如表所示。 表1 设备参数表 设备 接口 IP地址 子网掩码 默认网关 R1 S0/3/0 192.168.1.1 255.255.255.252 N/A Gi0/0/0 192.168.2.1 255.…

js判断是否为null,undefined,NaN,空串或者空对象

js判断是否为null,undefined,NaN,空串或者空对象 这里写目录标题 js判断是否为null,undefined,NaN,空串或者空对象特殊值nullundefinedNaN空字符串("")空对象(…

mysql实现存在则保存,不存在则更新

方式1 ON DUPLICATE KEY UPDATE 使用前提:表必须配置唯一键或者主键,且保存的字段中包含该键【重点】 原理: ON DUPLICATE KEY UPDATE如果配合主键,存在数据a,新插入b,如果主键不冲突,会保存b…

分布式监控平台-Zabbix

分布监控平台-Zabbix 一、Zabbix概述1、Zabbix是什么?2、Zabbix监控原理 二、部署Zabbix服务端(端口:10051)1、关闭防火墙 修改主机名2、获取Zabbix下载资源3、安装SCL(Software Collections),修改 Zabbix-front 前端源…

Analysis For Office的一些使用技巧

目录 1. 自由特性下钻停止刷新 2. 直接双击过滤内容 3.重复层级值 4. 从过滤值选参数 5.从Excel复制参数 6. 保存参数值 7.计划值回退到上一步 8. 保存当前导航步骤 1. 自由特性下钻停止刷新 一般我们每次拖一个自由特性到workbook里,报表都会自动刷新。如…

ARL灯塔(无需VPS版)

标题随便写,能看到都是有缘人 搭建灯塔那么繁琐的步骤,远不如爆破一个灯塔是吧(狗头) 而且还可能买不起VPS的情况(例如我) 那不如写一个脚本去爆破灯塔的弱口令 整治网络安全 从你我做起 fofa语法: icon_hash"1708240621"…

adk部署win10

adksetup.exe安装 百度搜索adk 在这里插入图片描述 https://docs.microsoft.com/en-us/windows-hardware/get-started/adk-install下载adk 注意:要和操作系统版本对应上,我这里是1903版本的win10。

探索未来的数字人生:全景VR数字人

在数字化时代,人工智能和虚拟现实技术正日益成为我们生活中不可或缺的一部分。而全景VR数字人,则是这一时代的最新产品,吸引了越来越多的关注和研究。 一、什么是全景VR数字人? 全景VR数字人是一种通过虚拟现实技术创造的数字人形…

中国移动发布COCA软硬一体片上计算架构,引领云计算市场下一个黄金十年

当前,数字经济发展已经成为改变全球竞争格局的关键力量,随着算力成为数字经济新引擎,算力规模持续增长,算力结构发生改变。主动拥抱智算浪潮,持续输出优质算力支撑数字中国建设,适配泛在化、异构化算力推动…

如何理解自动化测试数据驱动与关键字驱动的区别?

一、关键字驱动KDT(Keyword-driven testing) 1、自动化测试框架发展的第三个阶段是关键字驱动测试框架阶段,它是当前比较流行的一种框架之一,并且现在的自动化测试工具已经将关键字驱动框架融入到工具中。在录制过程中自动化测试工具会将对象及操作属性保…

在外Windows远程连接MongoDB数据库【无公网IP】

文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 转载自远程内网穿透的文章:公网远…

大数据Doris(六):BE部署及启动

文章目录 BE部署及启动 一、上传安装包并解压 二、修改be.conf 配置文件