EventFilter的作用域 ?
1. 只针对本 ui界面中的部件?2. 每个独立的 ui界面,都可以有一个不同作用域限定的:: 相同函数名的、内容相同的 event处理函数?
参考:
https://blog.csdn.net/ken2232/article/details/130272182
某些应用场景下,需要拦截某个组件发生的事件,让这个事件不再向其他组件进行传播,这时候可以为这个组件或其父组件安装一个事件过滤器(evenFilter)
设计思想,要点:拦截 <---> 不再向其他组件进行传播
前言
使用事件过滤器之前需要了解qt事件的运行机制。
这里举一个应用场景来记录事件过滤器的整个使用过程。
实现这样一个功能,在一个窗口上追踪鼠标的的移动位置,如果这个窗口是一个单一的窗口,没有任何子控件,那么只需要开启鼠标追踪,然后重写mouseMoveEvent(),就可以实现功能了。
但是如果有子控件的情况下,鼠标移动到子控件上时,移动事件会优先被子控件处理,那如果要在一个复杂的页面上完成这样的功能,岂不是需要重写所有子控件的鼠标事件?
事件过滤机制
Qt 在提供事件循环服务时,为了QObject提供了
bool eventFilter(QObject* watched, QEvent* event) override;
这个函数会在event()函数被调用之前调用,如果返回值为true,那么表示这个事件被处理了,这个事件将跳过event()函数的处理。
并且QObject还提供了
void QObject::installEventFilter(QObject *filterObj)
这个函数可以将一个QObject作为一个过滤器,安装到另一个QObject对象,那么安装之后,在调用自己本身的eventFilter()之前会先调用过滤器的这个函数。
事件过滤器可以设置多个,在调用时会根据安装的先后顺序调用。
示例
明白了这个机制之后,怎么实现前面的需求也就明了了,只需要创建一个QObject,然后重写eventFilter() 函数,在函数中实现对鼠标的追踪,然后再将这个过滤器安装到所有的子控件中即可。
#pragma once
#include <QWidget>
#include <QVBoxLayout>
#include <QLabel>
#include <QTextEdit>
namespace EFT {
class widget :public QWidget {
public:
widget(QWidget* parent = 0);
~widget();
protected:
bool eventFilter(QObject* watched, QEvent* event) override;
private:
QVBoxLayout* vLaout;
QLabel* label;
QTextEdit* textEdit;
};
}
#include "EventFilterTest.h"
#include <QEvent>
#include <QMouseEvent>
#include <QDebug>
EFT::widget::widget(QWidget* parent /*= 0*/)
:QWidget(parent)
{
//初始化窗口布局
vLaout = new QVBoxLayout();
label = new QLabel();
label->setText("This is a label");
textEdit = new QTextEdit();
vLaout->addWidget(label);
vLaout->addWidget(textEdit);
this->setLayout(vLaout);
//开启鼠标追踪
this->setMouseTracking(true);
label->setMouseTracking(true);
textEdit->viewport()->setMouseTracking(true);
//安装过滤器
label->installEventFilter(this);
textEdit->viewport()->installEventFilter(this);
this->installEventFilter(this);
}
EFT::widget::~widget()
{
textEdit->deleteLater();
label->deleteLater();
vLaout->deleteLater();
}
bool EFT::widget::eventFilter(QObject* watched, QEvent* event)
{
if (event->type() == QEvent::MouseMove)
{
auto e = dynamic_cast<QMouseEvent*>(event);
label->setText(QString("pos x: %1 y: %2").arg(e->globalX()).arg(e->globalY()));
return true;
}
return QWidget::eventFilter(watched, event);
}
运行结果: