概述
有时,需要对控件的某一类事件进行处理,而某一类则忽略。比如对话框需要拦截键盘事件不让其他控件接收等。
Qt
当中对于事件的分发和处理可以通过继承并实现event
函数实现,但随着组件的增多,这个操作就会变得多且繁琐,并且重写event
还得注意一大堆问题。
但Qt
提供了另一种方法去实现:事件过滤器(EventFilter)。
原型
1 | virtual bool QObject::eventFilter(QObject *watched, QEvent *event); |
此函数正如其名,为事件的过滤器。可以对我们接收到的事件进行筛选,留下想要的,或者继续分发不处理的。
使用
1 | // CustomWindow.h |
在这里,CustomWindow
是我们定义的一个用户界面,其中有个输入框。我们重写了它的evnetFilter
函数,当此时对象是输入框并且事件为键盘事件时,会输出此键并停止处理,将其过滤,返回true
,但是其他事件还是要处理的,所以返回false
。
对于其他的组件,我们不保证是否还有过滤器,所以交由父类处理。
注意事项
installEventFilter
可以向一个对象安装多个事件过滤器,只需要多次调用此函数。如果一个对象上安装有多个事件过滤器,那么最后一个安装的会第一个执行,遵循后进先出的原则。- 因为
installEventFilter
是类QObject
的函数,QApplication
与QCoreApplication
都是QObject
的子类。所以,我们可以向主程序添加事件过滤器,这种全局的事件过滤器会在所有其他特性对象的事件过滤器调用之前调用。虽然此种行为更加强大,但是也有其弊端,那就是会降低整个应用程序的事件分发效率。 - 当你在事件过滤器中
delete
了某个接收组件,务必将其返回值设置为true
,否则事件过滤器还是会将事件分发给改组件,导致程序崩溃。 - 事件过滤器和被安装的组件必须在同一线程,否则,过滤器不起作用。另外,如果在
install
之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效。 - 事件的调用最终都会调用
QCoreApplication
的notify
函数,因此,最大的控制权实际上是重写QCoreApplication
的notify()
函数。由此可以看出,Qt的事件处理实际上是分层五个层次:- 重定义事件处理函数;
- 重定义
event
函数; - 为单个组件安装事件过滤器;
- 为
QApplication
安装事件过滤器; - 重定义
QCoreApplication
的notify
函数。 - 这几个层次的控制权是逐层增大的。