Qt eventFilter

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(比如QComboBoxQSpinBox), 我们必须也子类化它们来表现出相同的行为. 一个更好的方案是让CustomerInfoDialog来监控它的子widget的按键事件,

在监测的代码里执行需要的行为. 这可以用event Filter来达到. 设置一个event filter有两个步骤:

  1. 在目标对象上调用installEventFilter() ,将监测对象注册到目标对象上.
  2. 在监测对象的eventFilter()方法里处理目标对象的事件.

在ctor里注册监测对象是一个好地方:

CustomerInfoDialog::CustomerInfoDialog(QWidget *parent) :QDialog(parent) 
{ 
... 
    firstNameEdit->installEventFilter(this); 
    lastNameEdit->installEventFilter(this); 
    cityEdit->installEventFilter(this); 
    phoneNumberEdit->installEventFilter(this); 
}

一旦event Filter注册了, 发送到firstNameEdit, lastNameEdit, cityEditphoneNumberEdit的事件在被发送到原来的目的地之前, 会先发到CustomerInfoDialogeventFilter()函数.

这是接收这些事件的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个级别来处理和过滤事件.

  1. 我们可以重新实现特定的event handler
    重新实现像mousePressEvent(), keyPressEvent()paintEvent()这样的event Handler是目前处理event最普通的方式.
  2. 我们可以重新实现QObject::event()
    通过重新实现event(),我们可以在事件到达特定的event handler之前对它们作出处理. 这个方法主要是用来覆写Tab键的缺省实现. 也可以用来处理不同发生的事件类型,对它们,就没有特定的event handler. 当重新实现event()的时候,我们必须调用基类的event()来处理我们不显式处理的情况.
  3. 我们可以安装一个event filter到一个单独的QObject.
    一旦一个对象用installEventFilter注册了, 发到目标对象的所有事件都会先发到监测对象的eventFilter(). 如果同一object安装了多个event filter, filter会依次被激活, **从最近安装的回到第一个. **
  4. 我们可以在QApplication对象上安装event filter.
    一旦一个event filter被注册到qApp(唯一的QApplication对象), 程序里发到每个对象的每个事件在发到其他event filter之前,都要首先发到eventFilter(). 这个方法对debugging非常有用. 也可以用来处理发到disablewidget上的事件, QApplication通常会丢弃它们.
  5. 我们可以子类QApplication并重新实现notify().
    Qt调用QApplication::notify()来发出事件. 在任何event filter得到之前, 重新实现这个函数是得到所有事件的唯一方法. event filter通常更有用, 因为可以有任意数目且同时存在的event filter, 但是只有一个notify()函数.

许多事件类型,包括鼠标和按键事件, 可以被传播. 如果一个事件没有在传到目标对象的过程中被处理,或者被目标对象本身处理, 整个事件处理过程会重复, 不过, 这次, 目标对象的parent作为新的目标对象. 从parentparent,这样继续下去,知道事件被处理了,或者到达了顶层的对象.

最后附上原文链接:http://www.cnblogs.com/smoozer/archive/2009/02/09/1386704.html 感谢

猜你喜欢

转载自blog.csdn.net/m0_37329910/article/details/88078971
QT