QT事件过滤器

一、Qt中事件过滤器详解

一.什么是事件过滤器?
事件过滤器是Qt中的一种机制,允许您在一个对象上截获和处理其他对象的事件。
通过使用事件过滤器,您可以在事件到达其目标对象之前拦截它,并对事件进行处理或修改。

2.为什么使用事件过滤器?
使用事件过滤器有以下几个优点:

1.事件过滤器可以提供更灵活的事件处理方式,因为它可以应用于多个对象。
2.事件过滤器可以用于对特定事件进行全局的拦截和处理,而不需要修改原始对象的代码。
3.事件过滤器可以实现对事件的修改、屏蔽或延迟处理等高级操作。
二.实现事件过滤器:
要实现事件过滤器,您需要创建一个继承自QObject的类,并重写它的eventFilter()函数。该函数会在事件到达对象时被调用,您可以在其中处理事件并返回布尔值来指示是否拦截该事件。

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

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

事件过滤器使用的三种方式:
1、父窗口类通过重写eventFilter方法来监听子控件的相关事件进行处理。
使用这种方式的好处是不需要通过重写控件的方式获取某些事件,对于安装了事件过滤器的对象,他们所有的事件都会经过这个事件过滤器,所以就可以直接在父窗口中进行监测。

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

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";
}

在这里插入图片描述
注意,因为Qt在按钮控件的内部也是通过事件的捕捉来发送信号的,这里过滤了按下事件会影响信号的发送,特此注意。

2、专门的事件过滤器类,对特定的对象/特定的事件进行处理
事件过滤器类只需对当前安装的对象进行处理,无需关心其他操作,且一个事件过滤器类可以被多个对象使用,例如Qt文档中的按键过滤示例,KeyPressEnter类中的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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值