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