IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> PyQt5中的父子(内外层)控件之间的事件传递关系 -> 正文阅读

[C++知识库]PyQt5中的父子(内外层)控件之间的事件传递关系

Qt界面设计涉及很多控件,控件之间的信息联系除了“信号-槽”机制外,还有内在的事件传输,所以了解事件的传递关系是精通Qt的必经之路。
在这里,我就PyQt5的代码内容讲解一下:父子(内外层)控件之间的事件传递关系、事件过滤器的作用以及两个事件控制函数。

更加详细的说明请看其他博主的Qt版原文:https://blog.csdn.net/xiaoyink/article/details/79398953

  1. 事件
    首先,我们得知道什么是Qt的事件。Qt中的事件主要有键盘触发事件、鼠标触发事件等关键的交互触发事件。我们可以通过重载控件中的事件触发函数,实现监控该事件的发生,并在事件发生后,立即执行必要的处理。比如下面提到的,对QLabel控件的鼠标按压事件触发函数mousePressEvent进行重载。

  2. 事件过滤器
    事件过滤器的作用就是对一个控件的所有发生事件事先进行拦截,在执行自定义的预处理后,按需要选择是否把事件传递下去。在PyQt5中,一般是对一个QWidget父控件内装载着很多子控件的情况下使用事件过滤器,用于对事件产生的控件和事件进行判断,并执行不同的处理。事件过滤器函数是 eventFilter(self, a0: ‘QObject’, a1: ‘QEvent’),一般使用形式为eventFilter(self, obj, event),obj表示事件产生的控件,event表示事件类型。并且对需要过滤的控件,需要显式安装事件过滤器。如下代码所示:

    class MyWidget(QWidget):
    def __init__(self, *args, **kwargs):
        super(MyWidget, self).__init__(*args, **kwargs)
        self.setWindowTitle('eventTest')
        self.resize(300, 300)

        self.label = QLabel()  # 建立一个标签
        self.label.setFrameShape(QFrame.Box)

        # 把标签装在外部widget上
        layout = QHBoxLayout()
        layout.addWidget(self.label)
        self.setLayout(layout)

        self.label.installEventFilter(self)  # 给label控件安装事件过滤器

	def eventFilter(self, obj, event):  # 事件过滤器
        print('here is eventFilter')
        
        return False

运行结果:
在这里插入图片描述

当鼠标进入、移出label控件控件,或者在label上左键单击、右键单击、双击以及鼠标滚轮滑动时,都会触发对应事件,并通过过滤器函数。
在这里插入图片描述

  1. 事件在父子控件的传递关系
    一般控件而言,事件的产生均先被父控件检测到,也就是说,如果有为子控件安装过滤器的话,事件都要经过过滤器再到达子控件的事件响应函数。并且,可以实现在过滤器中拦截事件:过滤器函数必须有返回值,返回值是bool类型。当过滤器函数返回True时,表示事件已经被处理掉,则事件不会再传递给子控件,相当于事件被拦截、被扼杀了;反之,返回False表示事件没有被处理,仍需要往下传递。下面用代码进行对比演示:
  # 先对Label控件进行重载,为了展示出鼠标按压函数被执行
class MyLabel(QLabel):
    def __init__(self, *args, **kwargs):
        super(MyLabel, self).__init__(*args, **kwargs)

    def mousePressEvent(self, event):  # 重载鼠标按压函数
        print('label had been pressed...')
        
class MyWidget(QWidget):
    def __init__(self, *args, **kwargs):
        super(MyWidget, self).__init__(*args, **kwargs)
        self.setWindowTitle('eventTest')
        self.resize(300, 300)

        self.label = MyLabel('label')  # 建立一个标签
        self.label.setFrameShape(QFrame.Box)  # 设置外框

        # 把标签装在外部widget上
        layout = QHBoxLayout()
        layout.addWidget(self.label)
        self.setLayout(layout)

        self.label.installEventFilter(self)  # 给label控件安装事件过滤器

    def eventFilter(self, obj, event):  # 事件过滤器
        if obj == self.label and event.type() == QEvent.MouseButtonPress:  # 判断控件和事件类型
            print('\nhere is eventFilter--------MouseButtonPress')
            return True  # 注意这里。。。。

        return False

下面是我多次鼠标单击label的结果,说明事件经过了过滤器:

然后修改一下过滤器函数的内容,把return True那语句删掉(注释掉):

def eventFilter(self, obj, event):  # 事件过滤器
    if obj == self.label and event.type() == QEvent.MouseButtonPress:
        print('\nhere is eventFilter--------MouseButtonPress')
        # return True  # 注意这里。。。。

    return False

多次单击鼠标,发现多了一行输出,此行输出来自上面重载的MyLabel中的鼠标按压触发函数。并且可以看出代码执行的顺序为:先经过过滤器,然后到达子控件内的事件触发函数。
在这里插入图片描述
对比上面两个不同的结果,可以很好的说明两点:
1) 子控件事件先被父控件检测到,然后再传递给子控件
2) 在过滤器返回True后,事件结束,不在往下传递;返回False,则继续往下传。

  1. 事件的两个控制函数
# event.accept() 表示事件已处理,不再继续传递事件,把事件拦截了
# event.ignore() 表示事件仍需进行下一步处理,对事件保留

event.accept()用于拦截事件,event.ignore()用于把事件保留,一般用于在重载子控件中的事件触发函数后,把事件再次抛出,让父控件也可以接受到。

# 先对Label控件进行重载,为了展示出鼠标按压函数被执行
class MyLabel(QLabel):
    def __init__(self, *args, **kwargs):
        super(MyLabel, self).__init__(*args, **kwargs)

    def mousePressEvent(self, event):  # 重载鼠标按压函数
        print('label had been pressed...')
        event.ignore()  # 如果没有这语句,则事件在此函数执行完成后消失

class MyWidget(QWidget):
    def __init__(self, *args, **kwargs):
        super(MyWidget, self).__init__(*args, **kwargs)
        self.setWindowTitle('eventTest')
        self.resize(300, 300)

        self.label = MyLabel('label')  # 建立一个标签
        self.label.setFrameShape(QFrame.Box)  # 设置外框

        # 把标签装在外部widget上
        layout = QHBoxLayout()
        layout.addWidget(self.label)
        self.setLayout(layout)

        self.label.installEventFilter(self)  # 给label控件安装事件过滤器

#  ------------此处增加父控件的鼠标按压重载函数----------------------
    def mousePressEvent(self, event):
        print('here is widget...')

    def eventFilter(self, obj, event):  # 事件过滤器
        if obj == self.label and event.type() == QEvent.MouseButtonPress:
            print('\nhere is eventFilter--------MouseButtonPress')
            # return True  # 注意这里。。。。

        return False

然后运行结果如下,表明了事件经过子控件,又传回了父控件,触发了父控件的事件触发函数:
在这里插入图片描述

那可能就有的伙伴就有疑问了:又说事件一开始是被父控件检测到的,为什么一开始不会触发父控件的事件触发函数呢?

这是因为鼠标单击是单击在label(子控件)上的,单击对象是label(子控件),这个事件是被label(子控件)捕捉到,应该归label(子控件)先处理,父控件只是检测到了label(子控件)捕捉到了一个事件但不是归它处理,所以要等子控件先处理此事件。重载子控件的事件处理函数可以自定义是否把事件继续回传给父控件(不加event.ignore()语句就是不回传);没有对子控件的事件处理函数重载的话,默认会回传给父控件。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-16 11:05:17  更:2021-07-16 11:07:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/27 23:09:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码