Qt-事件的发送顺序研究-1

        最近需要创建一个Qt的事件过滤器,现对Qt事件过滤器的运行机制做总结,重点是Qt事件的发送顺序。

        首先是Qt的事件过滤器的基本实现,采用了《C++ GUI Qt 4编程(第二版)》的例子。

        例子以一个CustomerInfoDialog覆盖原eventFilter(QObject *object, QEvent *event)接口,Dialog内各子QLineEdit作为目标对象,从而演示事件过滤器的用法。

        要点: (注意:这个例子的事件的监视对象是CustomerInfoDialog,是各ui->*Edit控件的父对象;同时,各ui->*Edit作为目标对象。)

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

 1 CustomerInfoDialog::CustomerInfoDialog(QWidget *parent) :
 2     QDialog(parent),
 3     ui(new Ui::CustomerInfoDialog)
 4 {
 5     ui->setupUi(this);
 6     ui->firstNameEdit->installEventFilter(this);
 7     ui->lastNameEdit->installEventFilter(this);
 8     ui->cityEdit->installEventFilter(this);
 9     ui->phoneNumberEdit->installEventFilter(this);
10 }

         2. 在监视对象的eventFilter()函数中处理目标对象的事件。(需要特殊处理的是键盘的空格点击事件;qDebug()语句用来提示事件的处理顺序)

 1 bool CustomerInfoDialog::eventFilter(QObject *target, QEvent *event)
 2 {
 3     if(target == ui->firstNameEdit || target == ui->lastNameEdit
 4             || target == ui->cityEdit || target == ui->phoneNumberEdit)
 5     {
 6         if(event->type() == QEvent::KeyPress)
 7         {
 8             qDebug() << "------------------";
 9             qDebug() << __FUNCTION__;
10             QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
11             if(keyEvent->key() == Qt::Key_Space)
12             {
13                 focusNextChild();
14                 return true;
15             }
16         }
17     }
18     return QDialog::eventFilter(target, event);
19 }

         根据书中的描述,一旦产生一个事件,会首先发送到eventFilter(...)接口处理。如果覆盖CustomerInfoDialog的keyPressEvent(...)事件,则发送至eventFilter的键盘事件会被keyPressEvent(...)事件处理器接收吗?

         以下代码覆盖CustomerInfoDialog::keyPressEvent(...)函数:

 1 void CustomerInfoDialog::keyPressEvent(QKeyEvent *event)
 2 {
 3     if(event->key() == Qt::Key_Space)
 4     {
 5         qDebug() << "------------------";
 6         qDebug() << __FUNCTION__ << event->isAccepted()
 7                  << "Space key pressed";
 8     }
 9     else
10     {
11         qDebug() << "------------------";        
12         qDebug() << __FUNCTION__ << event->isAccepted()
13                  << "Non-Space key pressed";
14     }
15 }

        如果空格键被按下,则eventFilter()成功检测到了空格键并执行focus移动的动作,而不是空格键默认的输入空格动作。同时,空格事件没有被keyPressEvent()接收。
              

        如果不是按下空格键而是其它键呢?比如尝试先按下: Shift,再按H键。

               

        可以发现,由于Shift因为不会被lineEdit控件处理,该事件先由CustomerInfoDialog::eventFilter()处理,然后发给lineEdit控件,因为lineEdit控件不处理Shift事件,事件又被转发至CustomerInfoDialog::keyPressEvent(...)处理。H键同样先由CustomerInfoDialog::eventFilter()处理,然后发给lineEdit控件,lineEdit控件显示键盘敲击的H字母,事件停止传送,CustomerInfoDialog::keyPressEvent(...)无法接收到H键点击事件。

        补充,虽然根据QObject的文档,"In your reimplementation of this function, if you want to filter the event out, i.e. stop it being handled further, return true; otherwise return false.",但是我改成return false似乎运行效果与return true一样?。。。

        完整代码如下:

        

        1. main.cpp:

 1 #include "CustomerInfoDialog.h"
 2 #include <QApplication>
 3 
 4 int main(int argc, char *argv[])
 5 {
 6     QApplication a(argc, argv);
 7     CustomerInfoDialog w;
 8     w.show();
 9     
10     return a.exec();
11 }

        2. CustomerInfoDialog.h

 1 #ifndef CUSTOMERINFODIALOG_H
 2 #define CUSTOMERINFODIALOG_H
 3 
 4 #include <QDialog>
 5 
 6 namespace Ui {
 7 class CustomerInfoDialog;
 8 }
 9 
10 class CustomerInfoDialog : public QDialog
11 {
12     Q_OBJECT
13     
14 public:
15     explicit CustomerInfoDialog(QWidget *parent = 0);
16     ~CustomerInfoDialog();
17     
18 protected:
19     bool eventFilter(QObject *target, QEvent *event);
20     void keyPressEvent(QKeyEvent *event);
21     
22 private:
23     Ui::CustomerInfoDialog *ui;
24 };
25 
26 #endif // CUSTOMERINFODIALOG_H

        3. CustomerInfoDialog.cpp

 1 #include "CustomerInfoDialog.h"
 2 #include "ui_CustomerInfoDialog.h"
 3 
 4 #include <QDebug>
 5 #include <QKeyEvent>
 6 
 7 CustomerInfoDialog::CustomerInfoDialog(QWidget *parent) :
 8     QDialog(parent),
 9     ui(new Ui::CustomerInfoDialog)
10 {
11     ui->setupUi(this);
12     ui->firstNameEdit->installEventFilter(this);
13     ui->lastNameEdit->installEventFilter(this);
14     ui->cityEdit->installEventFilter(this);
15     ui->phoneNumberEdit->installEventFilter(this);
16 }
17 
18 CustomerInfoDialog::~CustomerInfoDialog()
19 {
20     delete ui;
21 }
22 
23 bool CustomerInfoDialog::eventFilter(QObject *target, QEvent *event)
24 {
25     if(target == ui->firstNameEdit || target == ui->lastNameEdit
26             || target == ui->cityEdit || target == ui->phoneNumberEdit)
27     {
28         if(event->type() == QEvent::KeyPress)
29         {
30             qDebug() << "------------------";
31             qDebug() << __FUNCTION__;
32             QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
33             if(keyEvent->key() == Qt::Key_Space)
34             {
35                 focusNextChild();
36                 return false;
37             }
38         }
39     }
40     return QDialog::eventFilter(target, event);
41 }
42 
43 void CustomerInfoDialog::keyPressEvent(QKeyEvent *event)
44 {
45     if(event->key() == Qt::Key_Space)
46     {
47         qDebug() << "------------------";
48         qDebug() << __FUNCTION__ << event->isAccepted()
49                  << "Space key pressed";
50     }
51     else
52     {
53         qDebug() << "------------------";        
54         qDebug() << __FUNCTION__ << event->isAccepted()
55                  << "Non-Space key pressed";
56     }
57 }

        4. CustomerInfoDialog.ui

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <ui version="4.0">
  3  <class>CustomerInfoDialog</class>
  4  <widget class="QDialog" name="CustomerInfoDialog">
  5   <property name="geometry">
  6    <rect>
  7     <x>0</x>
  8     <y>0</y>
  9     <width>221</width>
 10     <height>152</height>
 11    </rect>
 12   </property>
 13   <property name="windowTitle">
 14    <string>CustomerInfoDialog</string>
 15   </property>
 16   <layout class="QVBoxLayout" name="verticalLayout">
 17    <item>
 18     <layout class="QGridLayout" name="gridLayout">
 19      <item row="0" column="0">
 20       <widget class="QLabel" name="fstNmLabel">
 21        <property name="text">
 22         <string>First Name:</string>
 23        </property>
 24        <property name="alignment">
 25         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
 26        </property>
 27       </widget>
 28      </item>
 29      <item row="0" column="1">
 30       <widget class="QLineEdit" name="firstNameEdit"/>
 31      </item>
 32      <item row="1" column="0">
 33       <widget class="QLabel" name="lstNmLabel">
 34        <property name="text">
 35         <string>Last Name:</string>
 36        </property>
 37        <property name="alignment">
 38         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
 39        </property>
 40       </widget>
 41      </item>
 42      <item row="1" column="1">
 43       <widget class="QLineEdit" name="lastNameEdit"/>
 44      </item>
 45      <item row="2" column="0">
 46       <widget class="QLabel" name="cityLabel">
 47        <property name="text">
 48         <string>City:</string>
 49        </property>
 50        <property name="alignment">
 51         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
 52        </property>
 53       </widget>
 54      </item>
 55      <item row="2" column="1">
 56       <widget class="QLineEdit" name="cityEdit"/>
 57      </item>
 58      <item row="3" column="0">
 59       <widget class="QLabel" name="phoneNumLabel">
 60        <property name="text">
 61         <string>Phone Number:</string>
 62        </property>
 63        <property name="alignment">
 64         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
 65        </property>
 66       </widget>
 67      </item>
 68      <item row="3" column="1">
 69       <widget class="QLineEdit" name="phoneNumberEdit"/>
 70      </item>
 71     </layout>
 72    </item>
 73    <item>
 74     <layout class="QHBoxLayout" name="horizontalLayout">
 75      <item>
 76       <spacer name="horizontalSpacer">
 77        <property name="orientation">
 78         <enum>Qt::Horizontal</enum>
 79        </property>
 80        <property name="sizeHint" stdset="0">
 81         <size>
 82          <width>40</width>
 83          <height>20</height>
 84         </size>
 85        </property>
 86       </spacer>
 87      </item>
 88      <item>
 89       <widget class="QPushButton" name="okButton">
 90        <property name="text">
 91         <string>OK</string>
 92        </property>
 93       </widget>
 94      </item>
 95     </layout>
 96    </item>
 97   </layout>
 98  </widget>
 99  <layoutdefault spacing="6" margin="11"/>
100  <resources/>
101  <connections/>
102 </ui>

        5. 项目.pro文件

 1 #-------------------------------------------------
 2 #
 3 # Project created by QtCreator 2018-11-28T19:26:05
 4 #
 5 #-------------------------------------------------
 6 
 7 QT       += core gui
 8 
 9 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10 
11 TARGET = CustomEventFilter
12 TEMPLATE = app
13 
14 # The following define makes your compiler emit warnings if you use
15 # any feature of Qt which has been marked as deprecated (the exact warnings
16 # depend on your compiler). Please consult the documentation of the
17 # deprecated API in order to know how to port your code away from it.
18 DEFINES += QT_DEPRECATED_WARNINGS
19 
20 # You can also make your code fail to compile if you use deprecated APIs.
21 # In order to do so, uncomment the following line.
22 # You can also select to disable deprecated APIs only up to a certain version of Qt.
23 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
24 
25 
26 SOURCES += \
27         main.cpp \
28         CustomerInfoDialog.cpp
29 
30 HEADERS += \
31         CustomerInfoDialog.h
32 
33 FORMS += \
34         CustomerInfoDialog.ui

 

posted @ 2018-11-28 21:34  r0xFED  阅读(676)  评论(0编辑  收藏  举报