Qt事件处理

一 事件介绍

事件是用户和应用软件间产生的一个交互操作,由用户操作产生或者系统内部产生,通过事件循环对事件进行处理,事件也可以用来在对象间进行信息交互。 . Qt平台会将系统产生的消息转换为Qt事件 .Qt事件是一个QEvent的对象 .Qt事件用来描述程序内部或外部发生的动作·任意的QObject对象都具备事件处理的能力

常见的事件如下: ·键盘事件:按键按下或松开 ·鼠标事件:鼠标移动。鼠标按键的按下和松开·拖放事件:用鼠标进行拖放 ·滚轮事件:鼠标滚轮滚动 ·绘屏事件:重绘屏幕的某些部分·

定时事件:定时器时间到达 大小改变事件:widgets的大小改变

二 事件处理

Qt's main event loop (QcoreApplication:exec()) fetches native window system events fromthe event queue,translates them into QEvents, and sends the translated events to QObjects.

Qt的主事件循环(QCoreApplication::exec())从事件队列中获取本机窗口系统事件,将它们转换为QEvent,并将转换后的事件发送到QObject

具体流程如下:

应用程序开始时(运行main()),会创建一个事件循环实例,通常是通过QCoreApplicationQApplicationexec()函数来启动事件循环。事件循环开始监听事件队列

事件可以由用户输入(如鼠标点击、键盘按键)或系统事件(如定时器事件、窗口事件)产生。事件首先被封装成QEvent类的一个实例,或者其子类,如QMouseEventQKeyEvent等。一旦事件被创建,它会被加入到Qt的事件队列中。

当有事件到达时,事件循环从队列中取出事件,根据事件的类型,将其分发给适当的目标对象。

 

QObjects receive events by having their Qobject::event() function called.The function canbe reimplemented in subclasses to customize event handling and add additional event types;QWidget:event() is a notable example.By default, events are dispatched to event handlerslike Q0bject::timerEvent() and QWidget:mouseMoveEvent(). QObject:.installEventFilter()allows an object to intercept events destined for another object. QObject通过调用QObject::event()函数来接收事件。该函数可以在子类中重新实现,以自定义事件处理并添加其他事件类型;QWidget::event()就是一个值得注意的例子。默认情况下,事件被分派到事件处理程序,如QObject:timerEvent()和QWidget::mouseMoveEvent()。Q0bject::install

具体流程如下:

当事件到达目标对象时,目标对象的事件分发器(通常是QObject::event())会被调用。在这个阶段,对象可以选择进一步处理事件,或者让事件沿着继承链向上传递。

目标对象可以通过重写特定的事件处理器方法来响应事件,如QWidget::keyPressEvent()QWidget::mousePressEvent()等。这些方法允许你自定义对象如何响应特定类型的事件。

在事件到达最终的目标对象之前,事件可以被其他对象过滤。

EventFilter()允许对象拦截发往另一个对象的事件。

 

事件先传播到当前产生事件的焦点控件上,经当前控件处理后决定是否传递给其父容器控件。

比如:pushbutton通过event函数接收事件后。通过事件类型调用对应事件处理函数进行处理。那么发送过来的事件会被父类默认event处理函数处理,它的处理就是发一个信号。对应的槽函数就会调用。

如果我们重写的event处理函数函数,可以做自己的处理。一般处理完了还会调用父类事件处理函数进行处理。

1 重写事件处理函数

新建立一个MyPushButoon

 

改成QushButton作为父类  

#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H

#include <QPushButton>

class MyPushButton : public QPushButton
{
    Q_OBJECT
public:
    explicit MyPushButton(QWidget *parent = nullptr);
    

};

#endif // MYPUSHBUTTON_H
#include "mypushbutton.h"

#include <QDebug>

MyPushButton::MyPushButton(QWidget *parent) : QPushButton(parent)
{

}

3 提升为自己控件  

槽函数 测试

4 重写事件处理函数

 头文件
 virtual void mousePressEvent(QMouseEvent *event);
 实现类
 void MyPushButton::mousePressEvent(QMouseEvent *event)
{
    qDebug()<< "mousePressEvent";

    //发信号
    //emit pressed();


    //调用一个父类事件处理,相当于自己处理完了,让父亲在处理一下 防止槽函数不会被调用
    QPushButton::mousePressEvent(event);
}

2 安装事件过滤器

事件过滤器可以对其他组件接收到的事件进行监控,任意的QObject对象都可以作为事件过滤器,使用事件过滤器对象需要重写eventFilter()函数事件过滤器在组件之前接收到事件 事件过滤器能够决定是否将事件转到组件对象  

在Qt中,事件过滤是一种机制,允许一个对象(称为事件过滤器)监听并处理原本发往另一个对象(称为目标对象)的事件。事件过滤提供了在事件被目标对象处理之前对其进行检查和潜在修改的能力。

事件过滤的意义在于提供了一种更高级别的事件控制手段。例如,你可以使用事件过滤器来:

  • 拦截事件:阻止某些事件被传递给目标对象,比如阻止鼠标点击事件导致窗口关闭。

  • 预处理事件:在事件到达目标对象之前做一些预处理工作,例如改变事件的参数,或者根据条件决定是否应该让事件继续传递。

  • 增强事件处理:在目标对象处理事件之前或之后添加额外的行为,例如记录日志、执行安全检查等。

事件过滤的流程如下:

  1. 当事件被分发时,Qt会检查目标对象是否安装了任何事件过滤器。

  2. 如果有事件过滤器安装在目标对象上,Qt会先调用事件过滤器的eventFilter()函数。

  3. eventFilter()函数接收三个参数:QObject *watched(被监听的对象)、QEvent *event(当前事件)和bool eventFilter(QObject *, QEvent *)(事件过滤器函数)。

  4. eventFilter()函数内部,你可以选择返回true来表示事件已经被处理,这样事件就不会再传递给目标对象。或者返回false表示事件未被处理,事件将继续传递给目标对象及其默认的事件处理函数。

  5. 如果事件过滤器没有处理事件(即返回false),事件将继续沿着事件分发链传递,直到找到一个可以处理它的对象,或者最终被忽略。

事件过滤在许多情况下都非常有用,尤其是在需要对用户界面的交互进行更细粒度控制的应用场景中。例如,在游戏开发中,你可能想要全局监听键盘事件以处理游戏控制,而不让这些事件影响到界面上的文本框或按钮。在这样的场景下,事件过滤器就可以用来拦截和处理这些事件,防止它们干扰游戏逻辑。

 

三 事件vs信号

信号由具体的对象发出,然后马上交给由connect()函数链接的槽进行处理;而对于事件,Qt使用一个事件队列对所有发出的事件进行维护,当新的事件产生的时候,会追加到事件队列尾部。

信号一旦发出,对应关联的槽函数一定会被执行。但是事件则可以使用"事件过滤器"进行过滤,对于有些事件进行额外的处理。另外的事件则不关心。

事件是有操作系统或者程序内部产生,由具体的对象处理。

信号由对象产生,由对象的槽函数来执行。

 

四 QEventLoop

QEventLoop是Qt框架中的一个核心组件,用于实现局部或临时的事件循环。在Qt中,主要的事件循环是由QCoreApplicationQGuiApplication提供的,它贯穿整个应用程序的生命周期。然而,有时候在某些特定的代码段中,你可能需要暂时停止代码的执行,等待某些事件发生,同时保持应用程序的其余部分响应用户输入和其他事件。这时,QEventLoop就派上了用场。

QEventLoop的一些主要用途:

  1. 等待异步操作完成: 当你需要等待一个耗时的异步操作(如网络请求、文件I/O)完成,而又不想阻塞整个应用程序时,可以使用QEventLoop。你可以在事件循环中等待特定的信号或条件变量被触发,从而知道异步操作已经完成。

  2. 防止界面卡死: 在GUI应用中,长时间运行的计算或等待操作会导致界面无响应,使用QEventLoop可以在执行这些操作的同时,仍然允许界面接收和处理事件,避免用户界面的卡顿。

  3. 模态对话框: 模态对话框通常需要阻止用户与主窗口的交互,直到对话框关闭。QEventLoop可以用于实现这种阻塞行为,同时仍然允许系统处理其他非用户输入的事件。

  4. 同步调用效果: 尽管Qt是基于异步和事件驱动的,但在某些情况下,你可能需要实现类似同步调用的行为,但又不希望完全阻塞线程。QEventLoop可以用来达到这种效果,例如在测试中等待特定的状态变化。

  5. 定时任务: 有时你可能需要在代码的某个点上延迟执行某段代码,但同时希望应用程序在此期间仍然响应其他事件。QEventLoop配合QTimer可以实现这种定时功能。

The QEventLoop class provides a means of entering and leaving an event loop.At any time,you can create a QEventLoop object and call exec() on it to start a local event loop.Fromwithin the event loop, calling exit() will force exec() to return. ​ QEventLoop类提供了一种进入和离开事件循环的方法。在任何时候,您都可以创建一个QEventLoop对象并在其上调用exec()来启动本地事件循环。在事件循环中,调用exit()将强制exec()返回。

在某个函数中,期望3s后再继续执行后面的逻辑。

方式一: QThread::sleep(3); 但是这个会将整个程序卡死,页面无法操作

方式二: QEventLoop

void MainWindow::on_pushButton_clicked()
{
    //如果主线程阻塞。。。整个界面的操作都做不了。
   // QThread::sleep(3);
    //qDebug()<<"start....";
   QEventLoop loop;
    QTimer::singleShot(3*1000,&loop,SLOT(quit()));//3秒后发型号通知事件循环
    qDebug()<<"start  Event Loop....";
   loop.exec();
    qDebug()<<"end  Event Loop....";
}

打开一个新窗口,让新窗口一直存在

void MainWindow::on_pushButton_2_clicked()
{
    MyDialog dialog;
    dialog.show();

    //for(;;);
    QEventLoop loop;
    //对话框结束后,要关闭事件循环
    connect(&dialog,&MyDialog::finished,&loop,&QEventLoop::quit);
    loop.exec();
    qDebug()<<"end  Event Loop....";

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值