Installing Event Filters
QT事件模块一个真正强大的特性是可以设置一个QObject的实例去监测另外一个QObject实例的事件,在被监测的实例see之前.
假设我们有一个CustomerInfoDialog
这样的widget
, 它由几个QLineEdit
组成.我们想用Spacer
键来转变focus
到下一个QLineEdit
。 这个非标准的行为可能对一个内部的程序很合适, 需要培训它的用户来使用它. 。一个直接的方法是子类QLineEdit
,然后重新实现keyPressEvent()
来调用focusNextChild()
, 像这样:
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Space)
{
focusNextChild();
}
else
{
QLineEdit::keyPressEvent(event);
}
}
这个方法有一个主要的弊端: 如果我们在这个 form
中用到几个不同类型的 widget
(比如QComboBox
和QSpinBox
), 我们必须也子类化它们来表现出相同的行为. 一个更好的方案是让CustomerInfoDialog
来监控它的子widget的按键事件,
在监测的代码里执行需要的行为. 这可以用event Filter
来达到. 设置一个event filter
有两个步骤:
- 在目标对象上调用
installEventFilter()
,将监测对象注册到目标对象上. - 在监测对象的
eventFilter()
方法里处理目标对象的事件.
在ctor里注册监测对象是一个好地方:
CustomerInfoDialog::CustomerInfoDialog(QWidget *parent) :QDialog(parent)
{
...
firstNameEdit->installEventFilter(this);
lastNameEdit->installEventFilter(this);
cityEdit->installEventFilter(this);
phoneNumberEdit->installEventFilter(this);
}
一旦event Filter
注册了, 发送到firstNameEdit
, lastNameEdit
, cityEdit
和phoneNumberEdit
的事件在被发送到原来的目的地之前, 会先发到CustomerInfoDialog
的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);
}
首先,我们检查是否目标widget
是一个QLineEdit
. 如果是个key Press
事件, 把它转换为QKeyEvent
, 并检查哪个键值被按下.
如果是space
, 我们调用focusNextChild()
把focus
传到focus
链上的下一个widget
上, 返回true告诉Qt我们已经处理了这个事件. 如果我们返回false, Qt会发送这个event到它原来的目的地,导致一个假的空格被插入到QLineEdit.
如果目标widget
不是QLineEdit
, 或者这个event
不是一个space
按键, 我们把控制权传回到基类的eventFilter
去. 目标wdiget
可以是基类-QDialog
正在监测的某个widget
.
Qt提供了5个级别来处理和过滤事件.
- 我们可以重新实现特定的
event handler
重新实现像mousePressEvent()
,keyPressEvent()
和paintEvent()
这样的event Handler
是目前处理event
最普通的方式. - 我们可以重新实现
QObject::event()
通过重新实现event()
,我们可以在事件到达特定的event handler
之前对它们作出处理. 这个方法主要是用来覆写Tab
键的缺省实现. 也可以用来处理不同发生的事件类型,对它们,就没有特定的event handler
. 当重新实现event()
的时候,我们必须调用基类的event()
来处理我们不显式处理的情况. - 我们可以安装一个
event filter
到一个单独的QObject
.
一旦一个对象用installEventFilter
注册了, 发到目标对象的所有事件都会先发到监测对象的eventFilter()
. 如果同一object
安装了多个event filter
,filter
会依次被激活, **从最近安装的回到第一个. ** - 我们可以在
QApplication
对象上安装event filter
.
一旦一个event filter
被注册到qApp
(唯一的QApplication对象), 程序里发到每个对象的每个事件在发到其他event filter
之前,都要首先发到eventFilter()
. 这个方法对debugging
非常有用. 也可以用来处理发到disable
的widget
上的事件,QApplication
通常会丢弃它们. - 我们可以子类
QApplication
并重新实现notify()
.
Qt调用QApplication::notify()
来发出事件. 在任何event filter
得到之前, 重新实现这个函数是得到所有事件的唯一方法.event filter
通常更有用, 因为可以有任意数目且同时存在的event filter
, 但是只有一个notify()
函数.
许多事件类型,包括鼠标和按键事件, 可以被传播. 如果一个事件没有在传到目标对象的过程中被处理,或者被目标对象本身处理, 整个事件处理过程会重复, 不过, 这次, 目标对象的parent
作为新的目标对象. 从parent
到parent
,这样继续下去,知道事件被处理了,或者到达了顶层的对象.
最后附上原文链接:http://www.cnblogs.com/smoozer/archive/2009/02/09/1386704.html 感谢