Qt Event事件详解 (*精*)

目录

Qt之事件过滤器(eventFilter)详解

eventFilter() 的返回值

Qt Event事件详解 (*精*)

参考:

QPushButton “双击”事件代码:测试OK (*****)

https://blog.csdn.net/ken2232/article/details/129561266

--------------------------------------

eventFilter() 的返回值

bool MainWindow::eventFilter(QObject *, QEvent *){

}

eventFilter() 的object参数表示事件发生的来源物件,

eventFilter()若返回false,则安装该事件过滤器的对象的event()会继续执行,

若返回true,则安装事件过滤器的对象后event()方法就不会被执行,由此进行事件的拦截处理,所以这块一定要注意

Qt鼠标点击不响应QMouseEvent事件的解决办法_qt chartview不执行鼠标响应_渡之的博客-CSDN博客

======================

注意区别:QEvent 和 EventFilter 过滤事件

思考(??????):event 与 eventFilter 的本质

1. event 与 eventFilter,是同一类的东西。相当于 MCU的中断。

2. eventFilter相当于 高优先级 的中断,event的优先级低。

因此,eventFilter抢先于 event运行,

并在 eventFilter中决定是否 屏蔽掉某个部件能够继续在 event中运行。

在复杂运用场景里,相当于多个中断可以被用来直接控制一个部件;或者通过复杂运算之后,再来控制一个部件。

3. 区别:以适用于不同的应用场景

event:相当于一把一把不同规格的螺丝刀。简单,方便,灵活。event 的零散应用。

eventFilter:相当于是螺丝刀套装,单独一把任意规格的螺丝刀能完成的功能,它都能完成。还能完成更加复杂的功能。event 集中处理,

Qt Event事件详解 (*精*)

一、简述

个人认为,事件机制是Qt最难以理解且最为精妙的一部分。事件主要分为两种

在与用户交互时发生:比如按下鼠标(mousePressEvent),敲击键盘(keyPressEvent)等。

系统自动发生:比如计时器事件(timerEvent)等。

在发生事件时(比如说上面说的按下鼠标),就会产生一个QEvent对象(这里是QMouseEvent,为QEvent的子类),这个QEvent对象会传给当前组件的event函数

如果当前组件没有安装事件过滤器(这个下文会提到),则会被event函数发放到相应的xxxEvent函数中(这里是mousePressEvent函数)。

Qt中所有的事件类都继承于QEvent类

这个QEvent对象会有各种各样的属性,这是由用户与界面交互时产生的。xxxEvent函数可以对其进行不同的处理(比如说是鼠标左键按下还是右键?)。查看帮助文档,可以看到QMouseEvent类有以下枚举。


在QtCreator中查看帮助文档

那么就可以在mousePressEvent中根据这个QEvent对象的这些枚举值来进行不同的处理,比如

class myLabel : public QLabel
{
protected:
    void mousePressEvent(QMouseEvent *event);
};

void myLabel::mousePressEvent(QMouseEvent *event)
{
    if(event->Buttons == LeftButton)
    {
        //do sth
    }
    else if(event->Buttons == RightButton)
    {
        //do sth
    }
}

可以看到,我们首先需要先创建一个自己的 QLabel类,并继承于Qt的 QLabel类,然后并重写相应的xxxEvent函数(这些事件处理函数都是虚函数)

Qt程序的main函数中需要创建一个QApplication对象,然后调用exec函数。这将令程序进入一个死循环,并不断监听应用程序的事件,发生事件时就生成一个QEvent对象。这又称为事件循环

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow window;
    window.show();

    return app.exec();
}

二、事件的分发:event函数

上面提到的xxxEvent函数,称为事件处理器(event handler)。

event函数的作用就在于事件的分发。如果想在事件的分发之前就进行一些操作,比如监听某个按键的按下。

        //将QEvent对象转换为真正的QKeyEvent对象
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);

     //按照原来的流程来进行事件的分发
    return QWidget::event(e);

bool myWidget::event(QEvent *e)
{
    if (e->type() == QEvent::KeyPress) 
    {
        //将QEvent对象转换为真正的QKeyEvent对象
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
        if (keyEvent->key() == Qt::Key_Tab) 
        {
            qDebug() << "You press tab.";
            return true;
        }
    }
    //按照原来的流程来进行事件的分发
    return QWidget::event(e);
}

在上面的程序中,myWidget是QWidget的子类。同样的,它的event函数是一个虚函数,带有一个QEvent类型的参数。当系统产生QEvent对象时,就会传入这个函数并调用。函数的返回值是bool类型,返回值不同有不同的意义。

如果传入的事件已被识别并且处理,则需要返回 true,否则返回 false。如果返回值是 true,那么 Qt 会认为这个事件已经处理完毕,不会再将这个事件发送给其它对象,而是会继续处理事件队列中的下一事件。
在这里插入图片描述

Qt系统在处理事件时,有一种机制叫事件传播机制。也就是说,在子组件(比如说一个QButton)中发生的事件,调用了子组件的event函数之后,还会调用父组件(比如说QWidget)的event函数。event函数的返回值就用于控制这样的一个过程。

需要注意的是,重写event函数之后:最好返回父类的event函数来处理其他的事件分发,不然就只能处理自己定义的事件

bool myTextEdit::event(QEvent *e)
{
    if (e->type() == QEvent::KeyPress) 
    {
        //将QEvent对象转换为真正的QKeyEvent对象
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e); //1.首先需要转换为 按键事件
        if (keyEvent->key() == Qt::Key_Tab)  //2.才能使用 按键的有关判断方法
        {
            qDebug() << "You press tab.";
            return true;
        }
    }
    //直接返回false
    return false;
}

在这个例子中,因为没有调用父类QTextEdit的event函数,所以只能处理Tab的情况,你再按其他按键就啥反应都没有了。同样,事件也不能进行传播。

三、事件过滤器(Even Filter)

要点:拦截 <---> 不再向其他组件进行传播

某些应用场景下,需要拦截某个组件发生的事件,让这个事件不再向其他组件进行传播这时候可以为这个组件或其父组件安装一个事件过滤器(evenFilter)。

QObject有一个虚函数,原型如下

virtual bool QObject::eventFilter ( QObject * watched, QEvent * event );

可以看到,函数有两个参数,一个为具体发生事件的组件,一个为发生的事件(产生的QEvent对象)。

事件是我们感兴趣的类型,可以就地进行处理,并令其不再转发给其他组件。函数的返回值也是bool类型,作用跟even函数类似,返回true为不再转发,false则让其继续被处理。

实际使用中,我们需要对QObject组件调用 installEvenFilter函数,即为组件安装过滤器,才能使用事件过滤器这个机制。这样,该组件及其子组件的事件就会被监听。这个机制的好处在于不用像重写QEvent和xxxEvent函数一样需要继承Qt的内置类。

void QObject::installEventFilter ( QObject * filterObj );

下面举一个例子。MainWindow中有一个QTextEdit控件,我们拦截它的键盘按下的事件。这样处理之后,会在输出窗口打印出按下的键位,但不会在控件上显示。这表明事件已被拦截,不会去调用even函数。

//当只有部分组件安装了、或需要安装 eventFilter;而另一些组件直接采用 xxxEvent函数时;

// 参考,上文:如果当前组件没有安装事件过滤器(这个下文会提到),则会被event函数发放到相应的xxxEvent函数中(这里是mousePressEvent函数)

           

//当不确定是否继续传播时,按照父类的方法来处理
        //即调用父类的evenFilter函数
        return QMainWindow::eventFilter(obj, event);

class MainWindow : public QMainWindow
{
public:
    MainWindow();
protected:
    bool eventFilter(QObject *obj, QEvent *event);
private:
    QTextEdit *textEdit;
};
 
MainWindow::MainWindow()
{
    textEdit = new QTextEdit;
    setCentralWidget(textEdit);
    
    textEdit->installEventFilter(this);
}
 
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if (obj == textEdit) 
    {
        if (event->type() == QEvent::KeyPress) 
        {
            QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
            qDebug() << "you press" << keyEvent->key();
            //事件不再进行传播,拦截
            return true;
        } 
        else
        {
            return false;//继续传播
        }
    } 
    else 
    {
        //当不确定是否继续传播时,按照父类的方法来处理
        //即调用父类的evenFilter函数
        return QMainWindow::eventFilter(obj, event);
    }
}

同样的,even函数能干的事情,evenFilter也能干。比如说上面的处理键盘按下Tab键。

bool myObject::eventFilter(QObject *object, QEvent *event)
{
    if (object == target && event->type() == QEvent::KeyPress) 
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if (keyEvent->key() == Qt::Key_Tab) 
        {
            qDebug() << "You press tab.";
            //拦截
            return true;
        } 
        else 
        {
            //不进行拦截
            return false;
        }
    }
    //不进行拦截
    return false;
}

我们可以对QApplication或者QCoreApplication对象添加事件过滤器。这种全局的事件过滤器将会在所有其它特性对象的事件过滤器之前调用。这种行为会严重降低整个应用程序的事件分发效率,要看具体情况使用

事件过滤器和被安装过滤器的组件必须在同一线程,否则,过滤器将不起作用。另外,如果在安装过滤器之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效。

四、总结

Qt中使用事件机制,每一种事件对应一个事件处理器,比如:

  • mouseEvent()
  • keyPressEvent()
  • etc…
    发生事件时会生成一个QEvent对象,则需要even函数进行分发,来调用相应的事件处理器
switch (event->type()) 
{
    case QEvent::MouseMove:
        mouseMoveEvent((QMouseEvent*)event);
        break;
    // ...
}

事件过滤器(evenFilter)可以令事件进行拦截,阻止其传播,从而实现某些功能。

另外,有一种一般很少使用的方法,即去重写这么一个函数

virtual bool QCoreApplication::notify ( QObject * receiver, QEvent * event );

该函数原实现相当于让组件调用even函数,即receiver->event(event)。这相当于全局的事件过滤器,且不会受到多线程的限制。

那么,在使用Qt的事件机制时,应该按照以下思路进行

  • 重写paintEvent、mousePressEvent等事件处理函数。这是最普通、最简单的形式,同时功能也最简单。
  • 重写event函数。event函数是所有对象的事件入口,QObject和QWidget中的实现,默认是把事件传递给特定的事件处理函数。
  • 在特定对象上面安装事件过滤器。该过滤器仅过滤该对象接收到的事件。
  • 在QCoreApplication::instance()上面安装事件过滤器。该过滤器将过滤所有对象的所有事件,但会有多线程问题。
  • 重写QCoreApplication::notify()函数。这是最强大的,和全局事件过滤器一样提供完全控制,并且不受线程的限制。

作者:Jacob杨帮帮
链接:https://www.jianshu.com/p/48f007c2de09
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

===========================================================

如果当前组件没有安装事件过滤器(这个下文会提到),则会被event函数发放到相应的xxxEvent函数中(这里是mousePressEvent函数)

 设计思想:

适用于不同的场景

  1. xxxEvent(如 mousePressEvent)::直接区分: 不同的事件,作用于不同(相同)的对象。
  2. event(QEvent *e)::对不同的事件,统一在一个 event型的函数中分别进行处理,需要区分事件的种类,不需要直接考虑区分作用对象。
  3. eventFilter(QObject *obj, QEvent *event)::包含了 对象的信息,因此,可以区分:相同的事件,作用于不同的对象。

===========================================

官方手册:

[virtual] bool QObject::event(QEvent *e)


This virtual function receives events to an object and should return true if the event e was recognized and processed.
The event() function can be reimplemented to customize the behavior of an object.
Make sure you call the parent event class implementation for all the events you did not handle.

[virtual] bool QObject::event(QEvent *e)

This virtual function receives events to an object and should return true if the event e was recognized and processed.
The event() function can be reimplemented to customize the behavior of an object.
Make sure you call the parent event class implementation for all the events you did not handle.
Example:

  class MyClass : public QWidget
  {
      Q_OBJECT

  public:
      MyClass(QWidget *parent = nullptr);
      ~MyClass();

      bool event(QEvent* ev) override
      {
          if (ev->type() == QEvent::PolishRequest) {
              // overwrite handling of PolishRequest if any
              doThings();
              return true;
          } else  if (ev->type() == QEvent::Show) {
              // complement handling of Show if any
              doThings2();
              QWidget::event(ev);
              return true;
          }
          // Make sure the rest of events are handled
          return QWidget::event(ev);
      }
  };

See also installEventFilter(), timerEvent(), QCoreApplication::sendEvent(), and QCoreApplication::postEvent().

[virtual] bool QObject::eventFilter(QObject *watched, QEvent *event)

Filters events if this object has been installed as an event filter for the watched object.
In your reimplementation of this function, if you want to filter the event out, i.e. stop it being handled further, return true; otherwise return false.
Example:

  class MainWindow : public QMainWindow
  {
  public:
      MainWindow();

  protected:
      bool eventFilter(QObject *obj, QEvent *ev) override;

  private:
      QTextEdit *textEdit;
  };

  MainWindow::MainWindow()
  {
      textEdit = new QTextEdit;
      setCentralWidget(textEdit);

      textEdit->installEventFilter(this);
  }

  bool MainWindow::eventFilter(QObject *obj, QEvent *event)
  {
      if (obj == textEdit) {
          if (event->type() == QEvent::KeyPress) {
              QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
              qDebug() << "Ate key press" << keyEvent->key();
              return true;
          } else {
              return false;
          }
      } else {
          // pass the event on to the parent class
          return QMainWindow::eventFilter(obj, event);
      }
  }

Notice in the example above that unhandled events are passed to the base class's eventFilter() function, since the base class might have reimplemented eventFilter() for its own internal purposes.
Some events, such as QEvent::ShortcutOverride must be explicitly accepted (by calling accept() on them) in order to prevent propagation.
Warning: If you delete the receiver object in this function, be sure to return true. Otherwise, Qt will forward the event to the deleted object and the program might crash.
See also installEventFilter().

Qt之事件过滤器(eventFilter)详解

1.2.1 Qt中事件是如何进行传递
1.2.2 Qt中的事件过滤器(eventFilter)
1.2.3 如何自己模拟发送事件消息
一、Qt中事件过滤器详解

我们先看下另外两个相关的方法,一个是给对象安装某个事件过滤器,一个是移除对应的事件过滤器。

    void QObject::installEventFilter(QObject *filterObj)
    void QObject::removeEventFilter(QObject *obj)

下方代码使用 installEventFilter方法 给对象objA安装objB的事件过滤器,这样objB对象的eventFilter方法中就可以接收到objA对象的所有事件了,如果objA对象不想objB对象再监听自己的事件了就使用 removeEventFilter方法移除objB对象对事件的监听。

    QObject* objA = new MyQObjectA;
    QObject* objB = new MyQObjectB;
    // 安装事件过滤器;    
    objA->installEventFilter(objB);
    // 移除事件过滤器;
    objA->removeEventFilter(objB);

    bool QObject::eventFilter(QObject *watched, QEvent *event)

事件过滤器我们听到这个名字可能就会理解为对事件进行过滤,但是实际上,事件过滤器并不只是过滤事件,也可以对事件进行捕捉、并做出相应的处理操作。对象A只有安装了对象B的事件过滤器,才会在对象B的eventFilter方法中进行监控对象A的所有事件。

在这里插入图片描述
事件过滤器使用的三种方式:

1、父窗口类通过重写eventFilter方法来监听子控件的相关事件进行处理。
使用这种方式的好处是不需要通过重写控件的方式获取某些事件,对于安装了事件过滤器的对象,他们所有的事件都会经过这个事件过滤器,所以就可以直接在父窗口中进行监测。比如某个窗口中有个QLabel对象,我们想要监听他的鼠标点击事件,那我们就需要继承QLabel类,然后重写mousePressEvent事件,如果有其他类型的控件也需要获取某个事件,那是不是都需要继续控件并重写某个事件了,所以我们通过事件过滤器就可以很方便获取某个对象的某个事件。

下面这个例子中MyLineEdit和MyBtn继承了QLineEdit和QPushButton,分别重写了两者的键盘按下(keyPressEvent)和鼠标按下事件(mousePressEvent),然后在他们的父窗口EventTestWgt中重写了事件过滤器(eventFilter),并给MyLineEdit和MyBtn对象及本身都安装了事件过滤器。
在此过滤器中捕捉到相应的事件,通过返回true,过滤输入框的键盘按下事件、过滤按钮的鼠标按下事件,过滤本身的鼠标按下事件,通过返回false,让本身的键盘按下事件继续传递,所以我们看到MyLineEdit的keyPressEvent方法、MyBtn的mousePressEvent以及EventTestWgt的mousePressEvent都不会被调用,只有EventTestWgt的keyPressEvent会被调用。

通过这个例子,我们看到事件过滤器可以对本身以及其他类的对象捕捉事件进行处理/过滤,同时也验证了第一种方式中的说法,可以不继承QLineEdit或者QPushButton就可以捕获子部件的相关事件进行处理,不需要对此类进行重写。
EventTestWgt.h

class MyLineEdit : public QLineEdit
{
public:
    MyLineEdit(QWidget* parent = nullptr);

private:
    void keyPressEvent(QKeyEvent *event);
};

class MyBtn : public QPushButton
{
    Q_OBJECT

public:
    MyBtn(QWidget* parent = nullptr);

private:
    void mousePressEvent(QMouseEvent *event);
};

class EventTestWgt : public QWidget
{
    Q_OBJECT

public:
    EventTestWgt(QWidget *parent = nullptr);
    ~EventTestWgt();

private:
    void initWgt();
    void initConnections();

private:
    void keyPressEvent(QKeyEvent *event);
    void mousePressEvent(QMouseEvent *event);

private:
    bool eventFilter(QObject *watched, QEvent *event);

private slots:
    void onBtnClicked();

private:
    MyLineEdit* m_lineEdit;
    MyBtn* m_pBtn;
};

 
 

EventTestWgt.cpp

#include "EventTestWgt.h"
#include <QDebug>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QEvent>

MyLineEdit::MyLineEdit(QWidget* parent /*= nullptr*/)
    : QLineEdit(parent)
{
}

void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
    qDebug() << "MyLineEdit::keyPressEvent" << event->key();

    return QLineEdit::keyPressEvent(event);
}

MyBtn::MyBtn(QWidget* parent /*= nullptr*/)
{
}

void MyBtn::mousePressEvent(QMouseEvent *event)
{
    qDebug() << "MyBtn::mousePressEvent";

    return QPushButton::mousePressEvent(event);
}

EventTestWgt::EventTestWgt(QWidget *parent)
    : QWidget(parent)
{
    initWgt();
    initConnections();
    
    this->resize(300, 200);
}

EventTestWgt::~EventTestWgt()
{
}

void EventTestWgt::initWgt()
{
    // 给自己安装事件过滤器;
    this->installEventFilter(this);

    // 给输入框和按钮都安装上事件过滤器;
    m_lineEdit = new MyLineEdit;
    m_lineEdit->installEventFilter(this);

    m_pBtn = new MyBtn;
    m_pBtn->setText("MyBtn");
    m_pBtn->installEventFilter(this);

    QHBoxLayout* hLayout = new QHBoxLayout(this);
    hLayout->addStretch();
    hLayout->addWidget(m_lineEdit);
    hLayout->addStretch();
    hLayout->addWidget(m_pBtn);
}

void EventTestWgt::initConnections()
{
    connect(m_pBtn, &QPushButton::clicked, this, &EventTestWgt::onBtnClicked);
}

void EventTestWgt::keyPressEvent(QKeyEvent *event)
{
    qDebug() << "EventTestWgt::keyPressEvent";
    
    return QWidget::keyPressEvent(event);
}

void EventTestWgt::mousePressEvent(QMouseEvent *event)
{
    qDebug() << "EventTestWgt::mousePressEvent";
    
    return QWidget::mousePressEvent(event);
}

bool EventTestWgt::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == m_lineEdit)
    {
        // 过滤处理输入框键盘按下事件;
        if (QEvent::KeyPress == event->type())
        {
            // todo;
            return true;
        }
    }
    
    if (watched == m_pBtn)
    {
        // 过滤处理MyBtn的鼠标按下事件;
        if (QEvent::MouseButtonPress == event->type())
        {
            // todo;
            return true;
        }
    }
    
    if (watched == this)
    {
        // 过滤处理自己的鼠标按下事件;
        if (QEvent::MouseButtonPress == event->type())
        {
            // todo;
            return true;
        }
        
        // 对自己的键盘按下事件不处理;
        if (QEvent::KeyPress == event->type())
        {
            // todo;
            return false;
        }
    }
    
    return QWidget::eventFilter(watched, event);
}

void EventTestWgt::onBtnClicked()
{
    qDebug() << "EventTestWgt::onBtnClicked";
}

 
 

下方是本示例的事件传递图,通过此图我们可以很清晰地看到事件传递的顺序、不同类之间事件的传递以及事件过滤器的作用。
在本例中我们过滤了按钮的鼠标按下事件(mousePressEvent),我特意在代码中加了此按钮点击的信号槽连接,实际因为鼠标事件被过滤,槽函数未被触发,因为Qt在按钮控件的内部也是通过事件的捕捉来发送clicked信号的,我们这里过滤了按下事件,影响了信号的发送,所以大家在重写或者过滤事件的时候需要注意。
本例中事件传递流程图

在这里插入图片描述

2、专门的事件过滤器类,对特定的对象/特定的事件进行处理。
事件过滤器类只需对当前安装的对象进行处理,无需关心其他操作,且一个事件过滤器类可以被多个对象使用,例如Qt文档中的按键过滤示例,KeyPressEater类中的eventFilter过滤了所有的键盘按下事件,只要安装此事件过滤器的控件,都接收不到键盘按键按下的事件,这种就是对某个通用的事件进行过滤,可以进行多次复用。

  class KeyPressEater : public QObject
  {
      Q_OBJECT
      ...

  protected:
      bool eventFilter(QObject *obj, QEvent *event) override;
  };

  bool KeyPressEater::eventFilter(QObject *obj, QEvent *event)
  {
      if (event->type() == QEvent::KeyPress) {
          QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
          qDebug("Ate key press %d", keyEvent->key());
          return true;
      } else {
          // standard event processing
          return QObject::eventFilter(obj, event);
      }
  }
 
    void test()
    {
        KeyPressEater *keyPressEater = new KeyPressEater(this);
        QPushButton *pushButton = new QPushButton(this);
        QListView *listView = new QListView(this);
        
        pushButton->installEventFilter(keyPressEater);
        listView->installEventFilter(keyPressEater);
    }

3、给QApplication安装事件过滤器,达到全局事件监听的效果。
在notify方法下发事件的时候,QApplication对象可以拿到第一控制权,对某些事件优先进行处理,比如全局的快捷键操作。

使用上方的KeyPressEater类对全局的键盘按下事件进行过滤.

QApplication a(argc, argv);
KeyPressEater *keyPressEater = new KeyPressEater(&a);
a.installEventFilter(keyPressEater);

再提一点:

当一个对象安装多个事件过滤器的时候,我们通过文章上方提到,先安装的后调用,下方代码中EventFilterObjA和EventFilterObjB都实现了对鼠标按下事件的过滤,而EventFilterObjB类对象的事件过滤器是后安装的,所以先调用,我们运行代码发现,在EventFilterObjB中过滤完之后EventFilterObjA中的eventFilter就接收不到了,所以只要在一处先过滤,后面就都接收不到了,所以大家在实际运用过程中一定要注意,就算同是事件过滤器也分先后,先过滤了的事件,后面就再也收不到了。

// 事件过滤器对象;
class EventFilterObjA : public QObject
{
public:
    EventFilterObjA(QObject* parent = nullptr)
    {}

private:
    bool eventFilter(QObject *watched, QEvent *event)
    {
        if (QEvent::MouseButtonPress == event->type())
        {
            qDebug() << "EventFilterObjA::eventFilter"
                << "Class Name:" << watched->metaObject()->className()
                << "Event:" << event->type();
            
            return true;
        }
    
        return QObject::eventFilter(watched, event);
    }
};

class EventFilterObjB : public QObject
{
public:
    EventFilterObjB(QObject* parent = nullptr)
    {}

private:
    bool eventFilter(QObject *watched, QEvent *event)
    {
        if (QEvent::MouseButtonPress == event->type())
        {
            qDebug() << "EventFilterObjB::eventFilter"
                << "Class Name:" << watched->metaObject()->className()
                << "Event:" << event->type();
            
            return true;
        }
    
        return QObject::eventFilter(watched, event);
    }
};

void test()
{
    QWidget* myWgt = new QWidget;
    // 创建事件过滤器对象;
    EventFilterObjA* eFilterObjA = new EventFilterObjA(myWgt);
    EventFilterObjB* eFilterObjB = new EventFilterObjB(myWgt);
    
    // 安装外部事件过滤器;
    myWgt->installEventFilter(eFilterObjA);
    myWgt->installEventFilter(eFilterObjB);
}


// 输出结果;
EventFilterObjB::eventFilter Class Name: QWidget Event: QEvent::MouseButtonPress

本例中事件传递流程图

在这里插入图片描述

我们通过上篇文章的分析得知,eventFilter的优先级是比较高的,一般来说我们很少通过重写QApplication的notify方法来监测某个控件的某个事件,那样太小题大做了,如果都这样做会导致notify异常庞大,效率也有所降低,所以较常用的就是本篇文章中讲到的事件过滤器方法,既可以监听自己,又可以监听其他对象。

注意点:

1、事件过滤器可以安装在任何继承QObject的对象上,也可以安装在QApplication对象上(全局事件过滤器);

2、事件过滤器(eventFilter方法)返回值true,表示将当前事件进行过滤,不会发送到对象本身;

如果返回false,表示对当前事件不做任何处理,会通过event()方法将事件分发给原来的对象

如果不知道怎么处理或者返回什么,那就返回父类的eventFilter方法(类似

return QObject::eventFilter(watched, event));

3、一个对象可以安装多个事件过滤器(也就是一个对象的事件可以被多个对象进行监控/处理/过滤), 并且最先安装的事件过滤器是最后被调用的,类似于栈的操作,先进后出;

4、一个事件过滤器可以被多个对象安装,但是如果在事件过滤器(eventFilter方法)中把该对象删除了, 一定要将返回值设为true否则 Qt会将事件继续分发给这个对象,从而导致程序崩溃


————————————————
版权声明:本文为CSDN博主「前行中的小猪」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/goforwardtostep/article/details/124824749

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值