【QT】事件分发器/事件过滤器/事件处理的介绍和使用

本文介绍了Qt中的事件分发函数event()和事件过滤器eventFilter()的使用,以及如何通过重写这些函数来拦截和处理不同类型的事件,如键盘按键和鼠标点击。详细讲解了事件处理的顺序和常见事件类型如QCloseEvent的应用。
摘要由CSDN通过智能技术生成

事件分发函数 event()

在这里插入图片描述

事件分发器:返回值 bool

如果返回时true,代表用户要处理事件,不再分发事件了。

  • 事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。
  • event()函数并不直接处理事件,而是将这些事件对象按照它们不同的类型,分发给不同的事件处理(eventhandler)。

因此如上所述,event()函数主要用于事件的分发。所以,如果你希望在事件分发之前做一些操作,就可以重写这个event()函数了。

event事件

#include <QEvent>
  • 用途:用于事件的分发
  • 也可以用作拦截事件(不建议)

例如,我们希望在一个QWidget组件中监听 tab 键的按下,那么就可以继承QWidget,并重写它的event()函数,来达到这个目的

在这里插入图片描述

//事件分发器
bool mylabel::event(QEvent *e)
{    
if(e->type() == QEvent::KeyPress)
    {
       静态类型转换
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(e);
        if(keyEvent->key()==Qt::Key_Tab)
        {
            qDebug()<<"tab had pressed";
            return true;
        }
    }
    return QWidget::event(e);
}

做一个拦截的目的时,说明它可以做拦截。

实际应用就是鼠标事件就用鼠标相应的函数操作,定时器就用定时器。


//事件分发器
bool mylabel::event(QEvent *e)
{
 //如果键盘按下,在event事件分发中做拦截操作
    if(e->type() == QEvent::MouseButtonPress)
    {
        //静态类型转换
         QMouseEvent *ev = static_cast<QMouseEvent*>(e);
         QString str = QString("Event函数中,鼠标按下了 x = %1,y=%2 globalX =%3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
         qDebug()<<str;
    }

}

//会做类型检查,相对安全,但是带来的成本高于static_cast

 QMouseEvent *ev  = dynamic_cast<QMouseEvent*>(e);//会做类型检查,相对安全,但是带来的成本高于static_cast

事件过滤器(了解即可)

  1. 事件过滤器可以对需要的组件接收到的事件进行过滤,以及监控
  2. 任意的QObject对象都可以作为事件过滤器使用
  3. 事件过滤器的实现,需要重写eventFilter()函数
  4. 组件要想被监控,则需要通过installEventFilter()安装事件过滤器
  5. 事件过滤器能够决定是否将事件转发给组件对象,如下图所示:

在这里插入图片描述

obj->installEventFilter(filterObject);常常是obj->installEventFilter(this).

  • 发送到obj的所有事件, 都会先发送到filterObject的eventFilter()方法,
  • 即filterObject会过滤obj的事件, 这样就不用为了实现一个事件而要去继承, 再实现一个类, 完成如mouse event, key event等了, 只用在当前类中就可以通过事件过滤来完成.

在这里插入图片描述

在程序将事件分发到事件分发器前,可以利用过滤器拦截

1.给控件安装事件过滤器

2.重写eventFilter函数(obj,sv)

public:
    explicit Event(QWidget *parent = nullptr);
    ~Event();
    //重写事件过滤器事件
    bool eventFilter(QObject*obj,QEvent*e);
#include "event.h"
#include "ui_event.h"
#include <QDebug>
#include <QMouseEvent>
#include <QEvent>
Event::Event(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Event)
{
    ui->setupUi(this);
    //步骤一安装事件过滤器
    ui->label->installEventFilter(this);
    //步骤2L重写eventfilter事件
}

 bool Event::eventFilter(QObject*obj,QEvent*e)
 {
     if(obj == ui->label)
     {
     if(e->type() == QEvent::MouseButtonPress)
     {
         //静态类型转换
          QMouseEvent *ev  = dynamic_cast<QMouseEvent*>(e);//会做类型检查,相对安全,但是带来的成本高于static_cast
         //QMouseEvent *ev = static_cast<QMouseEvent*>(e);
          QString str = QString("EventFilter函数中,鼠标按下了 x = %1,y=%2 globalX =%3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
          qDebug()<<str;
      }
     }
     //其他默认处理
     return QWidget::eventFilter(obj,e);
 }
Event::~Event()
{
    delete ui;
}

在这里插入图片描述

Qt事件处理介绍

  • Qt平台会将系统产生的消息转换为Qt事件
  • Qt事件是一个QEvent的对象
  • Qt事件用来描述程序内部或外部发生的动作
  • 任意的QObject对象都具备事件处理的能力

如下图所示,可以看到QEvent的子类非常之多:

在这里插入图片描述

  • **QInputEvent:**用户输入事件
  • **QDropEvent:**用户拖放事件
  • **QPaintEvent:**描述操作系统绘制GUI动作的事件
  • **QCloseEvent:**用户关闭窗口事件
  • **QTimerEvent:**计时器事件

事件处理方式顺序

1.Qt事件产生后立即被分发到QWidget对象

2.QWidget中的**event(QEvent*)**进行事件处理

3.event()根据事件类型调用不同的事件处理函数

4.在事件处理函数中发送Qt中预定义的信号

5.调用信号关联的槽函数

举个例子:

1.当点击按钮后,将会触发**鼠标事件,调用event(QEvent*)**成员函数

3.调用**mouseReleaseEvent(QMouseEvent*)**成员函数

4.调用**click()**成员函数

5.触发信号SIGNAL(clicked());

同样,当用户点击窗口的关闭按钮时,也会触发closeEvent()事件函数,该函数需要重写,才能实现

 void MainWindow::closeEvent(QCloseEvent *event)
{
     if (maybeSave())                        //如果还有需要保存的数据
    {
         writeSettings();
         event->accept();
    } 
     else                                    //取消关闭窗口
    {
         event->ignore();
    }
 }

类似的还有**keyEvent()**获取键盘事件函数, **keyReleaseEvent()**键盘按下事件函数,enterEvent光标进入组件事件函数, leaveEvent光标离开组件事件函数等等。

其中QCloseEvent继承与QEvent,在QEvent中常用成员函数有

void  accept ();    //接收者处理当前事件

void  ignore ();    //接收者忽略当前事件,忽略后,事件可能传递给父组件

bool isAccepted();  //判断当前事件是否被
  • 25
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt事件过滤器 Qt事件模型一个真正强大的特色是一个QObject 的实例能够管理另一个QObject 实例的事件。 让我们试着设想已经有了一个CustomerInfoDialog的小部件。CustomerInfoDialog 包含一系列QLineEdit. 现在,我们想用空格键来代替Tab,使焦点在这些QLineEdit间切换。 一个解决的方法是子类化QLineEdit,重新实现keyPressEvent(),并在keyPressEvent()里调用focusNextChild()。像下面这样: void MyLineEdit::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Space) { focusNextChild(); } else { QLineEdit::keyPressEvent(event); } } 但这有一个缺点。如果CustomerInfoDialog里有很多不同的控件(比如QComboBox,QEdit,QSpinBox),我们就必须子类化这么多控件。这是一个烦琐的任务。 一个更好的解决办法是: 让CustomerInfoDialog去管理他的子部件的按键事件,实现要求的行为。我们可以使用事件过滤器。 一个事件过滤器的安装需要下面2个步骤: 1, 调用installEventFilter()注册需要管理的对象。 2,在eventFilter() 里处理需要管理的对象的事件。 一般,推荐在CustomerInfoDialog的构造函数中注册被管理的对象。像下面这样: CustomerInfoDialog::CustomerInfoDialog(QWidget *parent) : QDialog(parent){ ... firstNameEdit->installEventFilter(this); lastNameEdit->installEventFilter(this); cityEdit->installEventFilter(this); phoneNumberEdit->installEventFilter(this); } 一旦,事件管理被注册,发送到firstNameEdit,lastNameEdit,cityEdit,phoneNumberEdit的事件将首先发送到eventFilter()。 下面是一个 eventFilter()函数的实现: bool CustomerInfoDialog::eventFilter(QObject *target, QEvent *event) { if (target == firstNameEdit || target == lastNameEdit || target == cityEdit || target == phoneNumberEdit) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); if (keyEvent->key() == Qt::Key_Space) { focusNextChild(); return true; } } } return QDialog::eventFilter(target, event); } 在上面的函数中,我们首先检查目标部件是否是 firstNameEdit,lastNameEdit,cityEdit,phoneNumberEdit。接着,我们判断事件是否是按键事件。如果事件是按键事件,我们把事件转换为QKeyEvent。接着,我们判断是否按下了空格键,如果是,我们调用focusNextChild(),把焦点传递给下一个控件。然后,返回,true通知Qt,我们已经处理了该事件。 如果返回false的话,Qt继续将该事件发送给目标控件,结果是一个空格被插入到QLineEdit中。 如果目标控件不是 QLineEdit,或者按键不是空格键,我们将把事件传递给基类的eventFilter()函数。 Qt提供5个级别
下面是一个简单的案例,演示如何使用全局事件分发和局部事件分发。 假设我们有一个主窗口 MainWindow,其中包含一个按钮 button。我们想要在用户点击按钮时执行一些操作,同时也想要在用户在窗口中移动鼠标时输出鼠标坐标。 ```python from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton from PyQt5.QtCore import QEvent, Qt class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle('事件分发示例') self.setGeometry(100, 100, 400, 300) # 创建一个按钮 self.button = QPushButton('按钮', self) self.button.setGeometry(100, 100, 100, 50) # 将按钮的点击事件连接到槽函数 self.button.clicked.connect(self.on_button_clicked) # 安装全局事件过滤器 qapp = QApplication.instance() qapp.installEventFilter(self) def on_button_clicked(self): print('按钮被点击了!') def eventFilter(self, obj, event): if event.type() == QEvent.MouseMove and obj == self: print('鼠标移动到了坐标:', event.pos()) return super().eventFilter(obj, event) if __name__ == '__main__': app = QApplication([]) window = MainWindow() window.show() app.exec_() ``` 在上面的代码中,我们创建了一个 MainWindow 窗口,其中包含一个按钮 button。我们将按钮的点击事件连接到 on\_button\_clicked 槽函数中。 我们还安装了一个全局事件过滤器,以便在应用程序中捕获所有事件。在事件过滤器中,我们检查了事件类型是否为鼠标移动事件,并且检查了事件对象是否为 MainWindow 窗口。如果是,则输出鼠标坐标。 当用户在窗口中移动鼠标时,我们可以看到鼠标坐标被输出到控制台。当用户点击按钮时,我们也可以看到按钮被点击了的消息被输出到控制台。这说明我们成功地使用了全局事件分发和局部事件分发

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值