Qt 安装事件过滤器installEventFilter

本文详细介绍了Qt中的事件过滤机制,包括如何通过安装事件过滤器来监视并处理目标对象的事件,以及不同级别的事件处理方式。并通过一个具体的示例展示了如何使用事件过滤器实现自定义的键盘事件处理。

Qt的事件模型一个强大的功能是一个QObject对象能够监视发送其他QObject对象的事件,在事件到达之前对其进行处理。

假设我们有一个CustomerInfoDialog控件,由一些QLineEdit控件组成。我们希望使用Space键得到下一个QLineEdit的输入焦点。一个最直接的方法是继承QLineEdit重写keyPressEvent()函数,当点击了Space键时,调用focusNextChild()

void MyLineEdit::keyPressEvent(QKeyEvent *event)

{

    if (event->key() == Qt::Key_Space) {

        focusNextChild();

    else {

        QLineEdit::keyPressEvent(event);

    }

}

这个方法有一个最大的缺点:如果我们在窗体中使用了很多不同类型的控件(QComboBoxQSpinBox等等),我们也要继承这些控件,重写它们的keyPressEvent()。一个更好的解决方法是让CustomerInfoDialog监视其子控件的键盘事件,在监视代码处实现以上功能。这就是事件过滤的方法。实现一个事件过滤包括两个步骤:

1.      在目标对象上调用installEventFilter(),注册监视对象。

2.      在监视对象的eventFilter()函数中处理目标对象的事件。

注册监视对象的位置是在CustomerInfoDialog的构造函数中:

CustomerInfoDialog::CustomerInfoDialog(QWidget *parent)

    QDialog(parent)

{

    ...

    firstNameEdit->installEventFilter(this);

    lastNameEdit->installEventFilter(this);

    cityEdit->installEventFilter(this);

    phoneNumberEdit->installEventFilter(this);

}

事件过滤器注册后,发送到firstNameEditlastNameEditcityEditphoneNumberEdit控件的事件首先到达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(event);

            if (keyEvent->key() == Qt::Key_Space) {

                focusNextChild();

                return true;

            }

        }

    }

    return QDialog::eventFilter(target, event);

}

首先,我们看是目标控件是否为QLineEdit,如果事件为键盘事件,把QEvent转换为QKeyEvent,确定被敲击的键。如果为Space键,调用focusNextChild(),把焦点交给下一个控件,返回true通知Qt已经处理了这个事件,如果返回falseQt将会把事件传递给目标控件,把一个空格字符插入到QLineEdit中。

如果目标控件不是QLineEdit,或者事件不是Space敲击事件,把控制权交给基类QDialogeventFilter()。目标控件也可以是基类QDialog正在监视的控件。(在Qt4.1中,QDialog没有监视的控件,但是Qt的其他控件类,如QScrollArea,监视一些它们的子控件)

 

Qt的事件处理有5中级别:

1.      重写控件的事件处理函数:如重写keyPressEvent()mousePressEvent()paintEvent(),这是最常用的事件处理方法,我们已经看到过很多这样的例子了。

2.      重写QObject::event(),在事件到达事件处理函数时处理它。在需要改变Tab键的惯用法时这样做。也可以处理那些没有特定事件处理函数的比较少见的事件类型(例如,QEvent::HoverEnter)。我们重写event()时,必须要调用基类的event(),由基类处理我们不需要处理的那些情况。

3.      QObject对象安装事件过滤器:对象用installEventFilter()后,所有达到目标控件的事件都首先到达监视对象的eventFilter()函数。如果一个对象有多个事件过滤器,过滤器按顺序激活,先到达最近安装的监视对象,最后到达最先安装的监视对象。

4.      QApplication安装事件过滤器,如果qApp(唯一的QApplication对象)安装了事件过滤器,程序中所有对象的事件都要送到eventFilter()函数中。这个方法在调试的时候非常有用,在处理非活动状态控件的鼠标事件时这个方法也很常用。

5.      继承QApplication,重写notify()Qt调用QApplication::nofity()来发送事件。重写这个函数是在其他事件过滤器处理事件前得到所有事件的唯一方法。通常事件过滤器是最有用的,因为在同一时间,可以有任意数量的事件过滤器,但是notify()函数只有一个。

许多事件类型,包括鼠标,键盘事件,是能够传播的。如果事件在到达目标对象的途中或者由目标对象处理掉,事件处理的过程会重新开始,不同的是这时的目标对象是原目标对象的父控件。这样从父控件再到父控件,知道有控件处理这个事件或者到达了最顶级的那个控件。

7.2显示了一个键盘事件在一个对话框中从子控件到父控件的传播过程。当用户敲击一个键盘,时间首先发送到有焦点的控件上(这个例子中是QCheckBox)。如果QCheckBox没有处理这个事件,Qt把事件发送到QGroupBox中,如果仍然没有处理,则最后发送到QDialog中。


 

转自:http://blog.youkuaiyun.com/iamdbl/article/details/1630043#

### Qt安装事件过滤器以处理焦点相关事件的方法 在 Qt 框架中,可以通过事件过滤器来捕获和处理焦点相关的事件。以下是详细的说明以及实现方法。 #### 实现步骤概述 为了处理焦点事件,需要创建一个继承自 `QObject` 的类,并重写其 `eventFilter()` 方法。接着,为目标对象调用 `installEventFilter()` 方法以安装事件过滤器。当目标对象接收到焦点事件时,这些事件会先传递到 `eventFilter()` 函数中进行处理[^1]。 #### 代码示例 以下是一个完整的代码示例,展示如何使用事件过滤器来捕获和处理焦点事件: ```cpp #include <QApplication> #include <QWidget> #include <QPushButton> #include <QDebug> #include <QEvent> class FocusEventFilter : public QObject { protected: bool eventFilter(QObject *obj, QEvent *event) override { if (event->type() == QEvent::FocusIn) { // 当获得焦点时触发 qDebug() << obj->objectName() << "获得了焦点"; return true; // 表示已处理此事件 } else if (event->type() == QEvent::FocusOut) { // 当失去焦点时触发 qDebug() << obj->objectName() << "失去了焦点"; return true; } // 返回 false 表示未处理当前事件,继续传递给原始对象 return QObject::eventFilter(obj, event); } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; QPushButton button1(&window); QPushButton button2(&window); button1.setObjectName("button1"); button2.setObjectName("button2"); button1.setText("按钮1"); button2.setText("按钮2"); button1.setGeometry(50, 50, 100, 30); button2.setGeometry(50, 100, 100, 30); FocusEventFilter filter; // 为两个按钮分别安装事件过滤器 button1.installEventFilter(&filter); button2.installEventFilter(&filter); window.show(); return app.exec(); } ``` #### 关键点解析 1. **事件类型检测** 在 `eventFilter()` 方法中,通过 `event->type()` 判断事件的具体类型。对于焦点事件,主要关注的是 `QEvent::FocusIn` 和 `QEvent::FocusOut` 类型[^2]。 2. **返回值的意义** 如果 `eventFilter()` 返回 `true`,则表示事件已经被处理完毕,不会进一步传递给原始对象;如果返回 `false`,则表示事件未被完全处理,仍需由原始对象或其他过滤器继续处理。 3. **适用范围** 可以为任意支持事件的对象(如窗口部件、按钮等)安装事件过滤器。这使得开发者能够灵活地监控和管理多个对象的焦点变化行为。 #### 注意事项 - 确保事件过滤器仅用于必要的场景,以免影响性能或造成不必要的复杂度。 - 需要合理设计 `eventFilter()` 的逻辑,避免因错误处理而导致应用程序异常运行。 --- ###
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值