【Qt开发】事件与信号/事件过滤器

news2024/11/25 5:00:49

事件与信号/事件过滤器

  • 事件
    • 一、事件的产生
    • 二、事件的派发
    • 三、事件类和事件类型
    • 四、事件的处理
  • 事件与信号
  • 事件过滤器

事件

Qt系统的图形化窗口是由事件驱动的。,点击鼠标、按键,改变窗口大小、最小化窗口、关闭窗口等都会产生相应的事件。
QWidget类的所有界面组件类的基类,QWdiget类定义了大量的处理事件相关的数据类型和接口函数。

一、事件的产生

当应用程序发生变化,如点击鼠标、按下键盘等,就会产生事件。
事件是对象,是QEvent类或其派生类的实例。

Qt的主事件循环(QCoreApplication::exec())从事件队列中获取本地窗口系统事件,将它们转换为QEvent,并将转换后的事件发送给QObject。QObject类调用函数QObject::event()来处理事件。

事件可以划分为3类:

  • 自主事件:是由窗口系统产生的事件。例如,QKeyEvent事件、QMouseEvent事件。自主事件会进入系统事件队列,然后被应用程序的事件循环逐个处理
  • 发布事件:是由Qt或应用程序产生的事件。例如,QTime定时器发送定时溢出时,Qt会自动QTimeEvent事件。应用程序使用静态的QCoreApplication::postEvent()产生发布事件。发布事件会进入Qt事件队列,然后被应用程序的事件循环逐个处理
  • 发送事件:是由Qt或应用程序定向发送给某个对象的事件。应用程序使用静态的QCoreApplication::sendEvent()产生发送事件,由对象的event()函数直接处理

自主事件和发布事件是异步的,也就是事件进入队列后系统去处理,程序不会在产生事件的地方停止进行等待

QCoreApplication::postEvent
(
	QObject *receiver
	,QEvent *event
	,int priority = Qt::NromalEventPriority
)
  • receiver:事件的接收者
    event:事件对象
    priority :事件的优先级
  • 发布事件之后,该函数会立即退出,不会等待事件处理完,发布事件是异步的
QCoreApplication::sendEvent
(
	QObject *receiver
	,QEvent *event
)
  • receiver:事件的接收者
    event:事件对象
  • 发送事件之后,需要等待事件处理完,发送事件是同步的

二、事件的派发

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();//事件循环
}

函数QApplication::exec()的主要功能就是不断的检查系统队列和Qt事件队列中是否有未处理的自主事件和发布事件。
如果有事件就派发给接收事件的对象去处理,事件循环还可以把相同的事件进行合并发送给接收事件的对象去处理。

注意,应用程序的事件循环只会处理自主事件和发布事件,而不会处理发送事件,因为发送事件是以同步模式运行的

学习两个派发事件的函数:

在事件队列未能及时被处理,导致用户界面出现卡顿无响应,
可以使用这个函数来派发事件队列中为处理的事件
static void QCoreApplication::processEvents
(
QEventLoop::ProcessEventFlags flags=QEventLoop::AllEvents
)
  • QEventLoop::AllEvents:处理所有事件
  • QEventLoop::ExcludeUserInputEvents:排除用户输入事件
  • QEventLoop::ExcludeSockstNoitEvents:排除网络socket的通知事件
  • QEventLoop::WaitForMoreEvents:如果没有未处理的事件,等待更多事件
static void QCoreApplication::sendPostEvents
(
	QObject *receiver=nullptr //接收者对象
	,int event_type=0 //事件类型
)

把QCoreApplication::postEvent()发送到Qt事件队列里的事件立刻派发出去。如果没指定事件类型,就派发所有给这个接收者的事件。如果接收者和事件类型都不指定,就派发给所有使用QCoreApplication::postEvent()发布的事件

三、事件类和事件类型

事件是QEvent或其派生类的实例。QEvent是所有事件类的基类,但是它不是抽象函数。它可以自己创建事件,其主要的几个函数如下:

函数描述
void accept()接收事件
void ignore()忽略事件
bool isAccepted()是否接收事件
bool isInputEvent()事件对象是不是QInputEvent或其派生类实例
bool isPointerEvent()事件对象是不是QPointerEvent或其派生类实例
bool isSinglePointEvent()事件对象是不是QSinglePointEvent或其派生类实例
void spontaneous()是不是自主事件,也就是窗口系统事件
QEvent::Type type()事件类型

调用ignore(),事件会派发给其父组件。

每一个事件都有唯一的的事件类型,也有对应的事件类,有的事件类可以处理多种类型的事件。

在这里插入图片描述

四、事件的处理

有对象接收到应用程序派发过来的事件后,会调用函数event()处理事件,event()是QObject类中定义的一个虚函数,原型如下:

bool QObject::event(QEvent *e);

参数e就是事件对象,通过e->type()来判断事件的类型,调用对应的处理函数。
例如:事件类是QEvent::Paint(需要重新绘制事件类型),就调用paintEvent()处理函数。我们只需要重写函数paintEvent()就能达到自己的目标。

QWidget类是所有组件类的基类,它重新实现了event(),并针对一写典型类型的事件定义了专门的事件处理函数。

在这里插入图片描述
如果需要处理的事件在QWidget中没有对应的事件处理函数,需要重写event(),判断事件类型后调用自己定义的事件处理函数。

事件与信号

事件和信号的区别在于,事件通常是窗口系统和应用程序产生的。信号则是由Qt定义或用户自定义的。Qt为界面组件定义的信号通常都是对事件的封装。

现在需要编写一个例子:设计一个标签类TMyLabel,该类继承QLabel,重写event()函数
,并且对QEvent::HoverEnter和QEvent::HoverLeave类型的事件进行处理。当光标移动到组件上,组件上文字的颜色为红色,离开组件上的文字为黑色。

	 tmylabel.h
#include <QWidget>
#include <QLabel>
#include <QEvent>
class TMyLabel : public QLabel
{
    Q_OBJECT
public:
    TMyLabel(QWidget *parten=nullptr);
private:
	//重写event
    bool event(QEvent *e);
	//重写鼠标双事件处理的函数
    void mouseDoubleClickEvent(QMouseEvent *event);
signals:
	//自定义信号
    void doubleClicked();
};
	tmyLabel.cpp
#include "tmylabel.h"

TMyLabel::TMyLabel(QWidget *parten):QLabel(parten)
{
    this->setAttribute(Qt::WA_Hover,true);
}

bool TMyLabel::event(QEvent *e)
{
    QPalette plet=this->palette();
    if(e->type()==QEvent::HoverEnter)
    {
        this->setText("鼠标进入");
        plet.setColor(QPalette::WindowText,Qt::red);
        this->setPalette(plet);
    }
    else if(e->type()==QEvent::HoverLeave)
    {
        this->setText("鼠标离开");
        plet.setColor(QPalette::WindowText,Qt::black);
        this->setPalette(plet);
    }
    //其他事件类型继续交给父类处理
    return QLabel::event(e);
}

void TMyLabel::mouseDoubleClickEvent(QMouseEvent *event)
{
    Q_UNUSED(event);
    emit doubleClicked();
}

事件过滤器

从事件与信号章节得知,我们需要重新处理事件需要重新定义一个新类,在新类中去重新函数event()或对应的事件处理函数。
QObject还提供了另一种方式来处理事件:事件过滤器。它可以将一个对象的事件委托给另一个对象来监视并处理。
例如:一个窗口可以作为其界面上的QLabel组件的事件过滤器,派发给QLabel组件的事件由窗口去处理,这样就不需要重新定义一个标签类啦。

实现事件过滤器需要用到两个函数:

安装事件过滤器:将自己注册给监视对象
void QObject::installEventFilter(QObject *filterObj);
参数 filterObj:监视对象

监视对象需要重新实现eventFilter(),对监视到的事件进行处理
bool QObject::eventFilter(QObject *watched, QEvent *event);
参数watched:被监视对象
参数event:事件对象
返回值:
	true(事件就不会在传播给其他对象)
	false(事件会继续传播给事件接收者做进一步处理)

代码例子:
widget.h

class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private:
    bool eventFilter(QObject *watched,QEvent *event);
private:
    Ui::Widget *ui;
};
	widget.cpp
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->label->installEventFilter(this);
    ui->label_2->installEventFilter(this);
}

Widget::~Widget()
{
    delete ui;
}

bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    if(watched==ui->label)
    {
        if(event->type()==QEvent::Enter)
        {
            ui->label->setStyleSheet("background-color:rgb(170,255,255)");
            ui->label->setText("走开,我不喜欢");
        }
        else if(event->type()==QEvent::Leave)
        {
            ui->label->setText("靠近我呀");
        }
    }
    else if(watched==ui->label_2)
    {
        if(event->type()==QEvent::Enter)
        {
            ui->label_2->setStyleSheet("background-color:rgb(85,255,127)");
            ui->label_2->setText("走开,我不喜欢");
        }
        else if(event->type()==QEvent::Leave)
        {
            ui->label_2->setText("靠近我呀");
        }
    }
    我们只处理了少数事件,其他的事情传播给父类处理(如QEvent::Paint事件没有处理),
    所以需要返回父类的eventFilter()
    如果直接返回true,界面上就不会显示文字啦
    return QWidget::eventFilter(watched,event);
}

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

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

相关文章

shuashuashua

CVE-2023-2130 靶标介绍&#xff1a; 在SourceCodester采购订单管理系统1.0中发现了一项被分类为关键的漏洞。受影响的是组件GET参数处理器的文件/admin/suppliers/view_details.php中的一个未知函数。对参数id的操纵导致了SQL注入。可以远程发起攻击。 通过标靶介绍可以知道…

通过域名和HTTPS上线MSF

使用受信任证书的Meterpreter载荷 现在大多数安全解决方案还会通过分析进出目标机器的流量来进行网络入侵检测。在这种情况下&#xff0c;很可能即使使用编码器绕过了防病毒软件&#xff0c;但有效载荷也会在尝试连接到我们的侦听器时被捕获和拦截。 # 准备工作 首先需要准备…

FPGA开发——UART回环实现之接收模块的设计

一、简介 因为我们本次进行串口回环的实验的对象是FPGA开发板和PC端&#xff0c;所以在接收和发送模块中先编写接收模块&#xff0c;这样可以在后面更好的进行发送模块的验证。&#xff08;其实这里先编写哪个模块&#xff09;都不影响&#xff0c;这里看自己心情&#xff0c;反…

大语言模型微调框架Unsloth:简化模型微调流程,提升模型性能

Unsloth 将 Llama-3、Mistral、Phi-3 和 Gemma 等大型语言模型的微调速度提高了 2 倍&#xff0c;内存使用量减少了 70%&#xff0c;而且准确性不会降低&#xff01; 特点 通过手动派生所有计算繁重的数学步骤和手写 GPU 内核&#xff0c;unsloth 可以在不更改任何硬件的情况…

IMU助力跑步参数评估

近期&#xff0c;中国研究团队开发了一种创新的跑步参数评估方法&#xff0c;巧妙结合了IMU和多模态神经网络技术&#xff0c;旨在深入研究并有效评估跑步时的步态参数。 科研团队采用IMU传感器&#xff0c;将其固定在跑者的脚踝处&#xff0c;以实时监测并记录跑步时脚踝的加速…

如何利用RPA自动化流程机器人优化企业财务流程

随着企业规模的扩大和业务的复杂性增加&#xff0c;财务流程管理成了一个关键而复杂的任务。传统的财务流程往往涉及大量的重复性、繁琐的工作&#xff0c;不仅效率低下&#xff0c;而且容易出错。为了解决这些问题&#xff0c;越来越多的企业开始引入RPA机器人流程自动化来优化…

JAVA集中学习第五周学习记录(二)

系列文章目录 第一章 JAVA集中学习第一周学习记录(一) 第二章 JAVA集中学习第一周项目实践 第三章 JAVA集中学习第一周学习记录(二) 第四章 JAVA集中学习第一周课后习题 第五章 JAVA集中学习第二周学习记录(一) 第六章 JAVA集中学习第二周项目实践 第七章 JAVA集中学习第二周学…

打开Office(word、excel、ppt)显示操作系统当前的配置不能运行此应用程序最全解决方案!

我以前用过分区助手把office从c盘挪到d盘了&#xff0c;从那以后office就用不了了&#xff0c;然后我就删了&#xff08;貌似没删干净&#xff09;。 最近由于有使用word的需求&#xff0c;所以我从学校官网找到正版软件的安装包&#xff0c;按照步骤重新卸载电脑中office残留…

基于Java的民宿管理系统

TOC springboot306基于Java的民宿管理系统 第1章 绪论 1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着电脑和笔记本的广泛…

【Mac】Downie 打开提示试用的解决办法?

前情 我们在使用 Downie 的时候&#xff0c;可能遇到提示试用的问题&#xff0c;如下图所示。 原因 旧版本的 Downie 没有卸载干净导致的。 解决办法 先使用 AppCleaner 卸载掉电脑上的 Downie 旧版本软件&#xff0c;必须使用 AppCleaner 卸载。重新安装 Downie 即可。

DNN代码实战

DNN的原理 神经网络通过学习大量样本的输入与输出特征之间的关系&#xff0c;以拟合出输入与输出之间的方程&#xff0c;学习完成后&#xff0c;只给它输入特征&#xff0c;它便会可以给出输出特征。神经网络可以分为这么几步&#xff1a;划分数据集、训练网络、测试网络、使用…

C++_2_nullptr关键字(3/3)

本节内容有C的NULL在前面打头阵&#xff0c;学起来犹如探囊取物。 先来分析一段代码&#xff0c;本段代码恰好也结合了上节的宏。 #include<iostream> using namespace std; void f(int x) { cout << "f(int x)" << endl; } void f(int* ptr) { …

Android Settings 跳转流程

我们知道在Settings中&#xff0c;各模块之间的Fragment基本都继承了DashboardFragment&#xff0c;当有点击事件时&#xff0c;就会回调DashboardFragment中的onPerferenceTreeClick()方法。 在onPreferenceTreeClick()方法中可以根据preference的key做事件拦截&#xff0c;如…

Linux线程实用场景

文章目录 前言生产者消费者模型1.基于阻塞队列特点实现使用 2.基于环形队列和信号量实现使用 读者写者模型实现思想 线程池实现 前言 生产者消费者模型和读者写者模型这些模型是用于在线程间协调和管理资源访问的模式, 我们在之前已经理解了线程的概念以及同步与互斥, 现在我们…

无人机之消费级和工业级,两者区别分析

消费级无人机和工业级无人机在多个方面存在显著差异&#xff0c;这些差异主要体现在搭载设备、应用领域、针对用户、使用条件、性能要求、营销模式以及价格等方面。以下是对两者区别的详细分析&#xff1a; 1. 搭载设备 消费级无人机&#xff1a;主要搭载相机&#xff0c;并配…

C++ | Leetcode C++题解之第337题打家劫舍III

题目&#xff1a; 题解&#xff1a; struct SubtreeStatus {int selected;int notSelected; };class Solution { public:SubtreeStatus dfs(TreeNode* node) {if (!node) {return {0, 0};}auto l dfs(node->left);auto r dfs(node->right);int selected node->val…

Windows禁止应用联网

转自两种方法阻止电脑上的软件彻底联网&#xff01; - 知乎 (zhihu.com) 但为了稳妥&#xff0c;自己还是稍微记录一下 1、创建bat脚本文件 创建文本-将下面的代码填入-保存为.bat文件 Echo Off SetLocal:beginecho: echo ****** 禁止文件夹联网 ****** echo:set /p folder…

Qt报“libpng warning: iCCP: known incorrect sRGB profile”问题解决方法

Qt开发应用程序&#xff0c;界面加载图片或按钮加载图标时&#xff0c;会遇到编译器报“libpng warning: iCCP: known incorrect sRGB profile”问题&#xff0c;原因为色彩配置问题&#xff0c;需要修正图像的ICC配置文件&#xff0c;将其转换成sRGB类型。不同操作系统解决方法…

停车场拓扑(parking lot topology)中的 bbr 与 aimd

bbr 讨论组有个有趣的问题&#xff1a;[bbr-dev] Parking lot topology 我此前也意识到这个问题(参见 pacing 之对错)&#xff0c;但几乎所有 cc 的建模都基于 dumbbell topology&#xff0c;parking lot topology 因其太 “不理想”&#xff0c;“不规则” 而无人讨论&#x…

11.2.软件系统分析与设计-数据库分析与设计

文章目录 数据库分析与设计步骤ER图和关系模型 需求分析阶段概念结构设计逻辑结构设计物理结构设计数据库实施与运维 数据库分析与设计 数据库设计属于系统设计的范畴。通常把使用数据库系统的系统统称为数据库应用系统&#xff0c;把对数据库应用系统的设计简称为数据库设计。…