【PySide6】信号(signal)和槽函数(slot),以及事件过滤器

news2025/7/20 13:04:58

说明

在PYQT中,父控件可以通过两种方式响应子控件的事件:

  • 通过信号(signal)和槽函数(slot)机制连接子控件和父控件
  • 父控件可以通过设置eventFilter()方法来监听响应子控件的事件

一、信号(signal)和槽函数(slot)

示例

在PYQT中,每个组件都可以发出信号(signal),表示某个事件发生了。父组件可以通过connect()方法将子组件的信号连接到自己的槽函数(slot)中,从而响应这个事件。
举个例子,在一个界面中,可能有一个按钮(btn),当用户点击按钮时,需要将用户的操作记录到日志中。这时,可以在父组件中定义一个槽函数(log),然后将按钮的clicked信号连接到这个槽函数中:

class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        
        # 创建一个按钮
        self.btn = QPushButton('Click me', self)
        
        # 将按钮的clicked信号连接到log槽函数中
        self.btn.clicked.connect(self.log)
        
    def log(self):
        # 记录日志
        print('Button clicked')

QThread 多线程

在 PyQt 中,可以使用信号和槽机制来实现不同线程之间的通信。在使用 QThread 时,可以将 QThread 的子类化与信号和槽机制结合使用来实现多线程编程。

以下是一个简单的示例,展示了如何在 QThread 中使用信号和槽函数:

from PySide6.QtCore import QThread, Signal

class Worker(QThread):
    finished = Signal()  # 定义一个信号

    def __init__(self):
        super().__init__()

    def run(self):
        # 这里可以执行耗时操作
        self.finished.emit()  # 发射信号

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.worker = Worker()
        self.worker.finished.connect(self.on_finished)  # 连接信号和槽函数

    def on_finished(self):
        # 这里可以进行 UI 更新等操作
        pass

    def start_work(self):
        self.worker.start()

在上面的示例中,我们定义了一个 Worker 类,它继承自 QThread 类。Worker 类中定义了一个 finished 信号,用于在耗时操作完成后发射信号。在 MainWindow 类中,我们创建了一个 Worker 对象,并将其 finished 信号连接到 on_finished 槽函数上。在 start_work 函数中,我们启动了 Worker 线程,耗时操作完成后会发射 finished 信号,从而触发 on_finished 槽函数的执行。

以下是另一个简单的示例,展示了如何在 QThread 中使用信号和槽函数:
```python
from PySide6.QtCore import QThread, Signal, Slot

class WorkerThread(QThread):
    new_data = Signal(str)

    def __init__(self):
        super(WorkerThread, self).__init__()

    def run(self):
        for i in range(20):
            data = "Data: " + str(i)
            self.new_data.emit(data)
            self.msleep(1000)

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.worker_thread = WorkerThread()
        self.worker_thread.new_data.connect(self.on_new_data)

        self.start_button = QPushButton("Start")
        self.start_button.clicked.connect(self.worker_thread.start)

        self.layout = QVBoxLayout()
        self.layout.addWidget(self.start_button)

        self.central_widget = QWidget()
        self.central_widget.setLayout(self.layout)
        self.setCentralWidget(self.central_widget)

    @Slot(str)
    def on_new_data(self, data):
        print("Received data:", data)

在上面的示例代码中,创建了一个WorkerThread类,该类继承自QThread,并包含一个new_data信号。在run方法中,通过emit方法发送new_data信号。在MainWindow类中,创建了一个WorkerThread实例,并将其new_data信号连接到on_new_data槽函数。当用户单击Start按钮时,调用worker_thread.start方法启动新线程。

在on_new_data槽函数中,打印接收到的数据。注意,on_new_data方法带有一个字符串参数,该参数类型必须与new_data信号的参数类型相同。这是通过在on_new_data方法上添加@Slot(str)装饰器来实现的。

总的来说,在pyside6中使用信号和槽函数来使用QThread非常简单,只需将信号连接到槽函数即可。但请注意要在正确的线程中使用信号和槽函数。如果将信号发射到不同的线程中,可能会导致应用程序崩溃或未定义的行为。

二、事件过滤器

在PySide6中,如果在一个widget中创建了另一个widget,那么新widget默认是不会响应父控件的事件的。如果需要让新widget能够响应控件的事件,可以通过设置事件过滤器来实现。

事件过滤器是一种机制,允许我们在任意widget上监视和过滤所有事件,包括父控件的事件。通过设置事件过滤器,可以将父组件接收到的事件传播到子组件中。

示例代码一,在父控件,子控件分别设置事件过滤器

以下是示例代码:
在这里插入图片描述

import sys

from PySide6.QtCore import QEvent
from PySide6.QtGui import Qt, QPainter
from PySide6.QtWidgets import QWidget, QApplication, QVBoxLayout, QLabel, QHBoxLayout


class ChildWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setObjectName('ChildWidget')
        self.setFixedSize(100, 100)
        self.label = QLabel("Child")
        # 子组件布局
        self.child_layout = QVBoxLayout(self)
        self.child_layout.addWidget(self.label, 1, alignment=Qt.AlignCenter)

    def eventFilter(self, obj, event):
        if obj == self and event.type() == QEvent.MouseButtonPress:
            print('ChildWidget eventFilter', event)
        return super().eventFilter(obj, event)

    # 设置子控件颜色
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.fillRect(self.rect(), Qt.red)


class ParentWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.setObjectName('ParentWidget')
        self.setAutoFillBackground(True)
        self.setFixedSize(200, 200)
        # 事件过滤器
        self.child = ChildWidget(self)
        self.child.installEventFilter(self)
        self.installEventFilter(self)
        # 父组件布局
        self.parent_layout = QHBoxLayout(self)
        self.parent_label = QLabel("Parent")
        self.parent_layout.addWidget(self.child, 1)
        self.parent_layout.addWidget(self.parent_label, 1, alignment=Qt.AlignCenter)

    def eventFilter(self, obj, event):
        if obj == self and event.type() == QEvent.MouseButtonPress:
            print('ParentWidget eventFilter', event)
        return self.child.eventFilter(obj, event)


if __name__ == '__main__':
    app = QApplication([])
    parent = ParentWidget()
    parent.show()
    sys.exit(app.exec())

示例代码二,在父控件事件中设置所有子控件的事件

在这里插入图片描述

from PySide6.QtCore import Signal, QObject, QEvent
from PySide6.QtWidgets import QWidget, QApplication, QTextEdit, QVBoxLayout, QPushButton, QHBoxLayout


class ChildWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setObjectName('ChildWidget')
        self.layout = QHBoxLayout(self)
        self.child_button = QPushButton("Child")
        self.layout.addWidget(self.child_button)

class ParentWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.setObjectName('ParentWidget')
        self.layout = QHBoxLayout(self)
        # parent_button
        self.parent_button = QPushButton("Parent")
        self.parent_button.installEventFilter(self)
        # ChildWidget
        self.child = ChildWidget(self)
        self.child.child_button.installEventFilter(self)

        self.layout.addWidget(self.child)
        self.layout.addWidget(self.parent_button)
        self.layout.stretch(2)

    def eventFilter(self, obj, event):
        if obj == self.child.child_button and event.type() == QEvent.MouseButtonPress:
            print('ChildWidget eventFilter', event)
        elif obj == self.parent_button and event.type() == QEvent.MouseButtonPress:
            print('ParentWidget eventFilter', event)
        return super().eventFilter(obj, event)


if __name__ == '__main__':
    app = QApplication([])
    parent = ParentWidget()
    parent.show()
    app.exec()

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

传输线的物理基础(三):传输线的瞬时阻抗

每个信号都有一个上升时间 RT,通常是从 10% 到 90% 的电压电平测量的。当信号沿传输线向下移动时,前沿在传输线上展开并具有空间范围。如果我们可以冻结时间并观察电压分布向外移动时的大小,我们会发现类似下图的东西。传输线上上升时间的长度…

Python中的三器一闭(详细版)

python中的三器一闭迭代器什么是迭代什么是可迭代对象判断数据是否可迭代什么是迭代器迭代器的本质使用迭代器取数据自定义迭代器生成器创建生产器的方法关键字yieldnext和send装饰器装饰器的功能定义装饰器闭包什么是闭包函数、匿名函数、闭包、对象 当做实参时的区别迭代器 …

Blazor_WASM之3:项目结构

Blazor_WASM之3:项目结构 Blazor WebAssembly项目模板可选两种,Blazor WebAssemblyAPP及Blazor WebAssemblyAPP-Empty 如果使用Blazor WebAssemblyAPP模板,则应用将填充以下内容: 一个 FetchData 组件的演示代码,该…

蓝桥杯-最优清零方案(2022省赛)

蓝桥杯-最优清零方案1、问题描述2、解题思路3、代码实现1、问题描述 给定一个长度为 N 的数列 1,2,⋯,A1,A2,...,ANA_1,A_2,...,A_NA1​,A2​,...,AN​ 。现在小蓝想通过若干次操作将 这个数列中每个数字清零。 每次操作小蓝可以选择以下两种之一: 1. 选择一个大于 0 的整数, 将…

杂记——18.VSCode的下载及使用

这篇文章,我们来讲一下VSCode,讲一下如何下载及使用VSCode 目录 1.VSCode的下载 1.1VSCode的简介 1.2VSCode的下载与安装 1.2.1下载 1.2.2安装 2.VSCode的使用 2.1界面 2.2基础设置 2.3禁用自动更新 2.3自动保存设置 2.4Vscode更换主题 2.5…

Hive面试题-HQL转换MapReduce底层核心逻辑剖析

视频可查看:https://www.bilibili.com/video/BV1RV41147Tb/?spm_id_from333.999.0.0&vd_source3ba3c3ba31427f60d734ede7a948de4a 原文地址:Hive学习之路 (二十)Hive 执行过程实例分析 - 扎心了,老铁 - 博客园 (c…

K_A14_012基于STM32等单片机驱动GY-25倾斜度角度模块 串口与OLED0.96双显示

K_A14_012基于STM32等单片机驱动GY-25倾斜度角度模块 串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RCGY-25倾斜度角度模块1.2、STM32F103C8T6GY-25倾斜度角度模块五、基础知识学习与相关资料下…

测试按方向的分类

按方向分(都是在系统测试阶段测试的) 功能测试:举例说明什么是功能 性能测试 ①压力测试:不断地增加压力,从而找到系统的极限 ②负载测试:系统在极限工作条件下,最多能持续多久——可能发生内存泄漏/溢出,导…

angular技术(持续更新)

css类绑定[class.color-blue]"isBlue()" 如果isBlue()返回为true 这里使用color-blue的class样式style样式绑定[style.background-color]"canclick ? blue: red" 组件与模块模块的元数据*declarations: 用于指定属于这个模块的视图类(View Cla…

CM6.3.2启用Kerberos(附问题解决)

基础准备支持JCE的jdk重新安装JCE的jdk(已正确配置跳过)删除/usr/java/下面的jdk,然后通过CM->管理->安全->安装Java无限制...重新安装后,配置Java(可选)主机->主机配置->搜java->Java主目录 配置路径主机->所有主机->设置->高级:Java配置Kerberos安…

[算法]插入排序

参考:《漫画算法-小灰的算法之旅》 目录 1、排序算法的思想 2、具体步骤 3、插入排序的优化 4、时间复杂度和空间复杂度 5、代码 1、排序算法的思想 维护一个有序区,把元素一个个插入有序区的适当位置,直到所有元素都有序为止。 2、具体…

多线程面试题

1. Sychronized的锁升级过程是怎样的? 2. Tomcat 中为什么要使用自定义类加载器? 3. 说说对线程安全的理解 4. 对守护线程的理解 5. 并发、并行、串行之间的区别 6. Java死锁如何避免? 7. 谈谈你对AQS的理解,AQS如何实现可重入锁&…

华为机试题:HJ107 求解立方根(python)

文章目录(1)题目描述(2)Python3实现(3)知识点详解1、input():获取控制台(任意形式)的输入。输出均为字符串类型。1.1、input() 与 list(input()) 的区别、及其相互转换方…

2023年品牌惊蛰节气海报赏析

今天是3月6日——惊蛰,春日渐暖,春雷乍起,北方大地正在迎来新生,小鸟在枝头欢叫、种子在努力发芽,各大品牌也赶早发布了最新的惊蛰节气海报。下面就来和我们一起看看吧。 1,中国日报 2,BDuck…

java日志

日志是软件开发的重要组成部分。一个精心编写的日志代码提供快速的调试,维护方便,以及应用程序的运行时信息结构化存储。日志记录确实也有它的缺点。它可以减缓的应用程序Log4jLog4j是Apache的一个开放源代码项目,通过使用Log4j,我…

Spring | 基础

1. IOC和DI IOC:控制反转,其思想是反转资源获取的方向,传统的资源查找方式要求组件向容器发起请求查找资源,作为回应,容器适时的返回资源。而应用了 IOC 之后,则是**容器主动地将资源推送给它所管理的组件…

Sectigo中间证书根证书说明

Sectigo SSL证书产品证书链主要分为两个版本,常见的的一种版本多,但随着安全性提升,证书链的加载方式变化,第二种版本证书链更具备安全需要,对此做了详细说明。一、兼容性最高版本,根证书算法:s…

BI 是如何数据分析的?

企业部署商业智能BI前,需要进行详细的分析,了解BI能为企业带来多少价值?如何提高工作效率的等等,今天我们就来聊一聊 BI 的工作原理。 一、BI的取数方式 商业智能BI是通过访问和连接业务系统数据源数据库的方式来进行取数的&…

记录gitlab和jenkins集成的过程

gitlab设置外发请求 首先在前面的几篇文章中,我们的gitlab和jenkins都安装好了,在这里我们就可以对gitlab 和jenkins进行集成操作处理。 首先设置gitlab的外发请求,如图所示: 先点击管理员,进入到管理中心后 先点击设置,然后点击…

劲霸男装:400+门店的销售佣金管理,如何实现一键发薪

陪伴一代人记忆的劲霸男装(下文简称「劲霸」),很多人应该都不陌生。 他们的门店遍布全国的大型商场及街边店铺,自1980起,发展已40余年,现拥有形象统一、规范管理的品牌专卖店2000多家。他们门店多&#xff…