1. 回顾事件传递的过程

①源头:操作系统   操作系统检测到用户的动作时,就会产生一个系统消息,系统消息就会被发送到正在运行的Qt应用程序中,
②应用程序收到系统消息后, 他会将系统消息翻译成对应的QEvent事件对象,并调用QObject::event()将该对象分发下去,
③事件对象被分发到当前用户正在操作的窗口部件上去 ,该窗口部件是一个Qwidget的子类对象,该对象收到这个事件之后, 就会调用QWidget::event()函数来处理 ,该函数内部再调用其他的子函数(如KeyPressEvent或mouseReleaseEvent)进行具体的事件处理。
④可能会再被出传递到其父组件对象
 

(1)操作系统检测到用户动作时,会产生一条系统消息,该消息被发送到Qt应用程序

(2)Qt应用程序收到系统消息后,将其转化为一个对应的QEvent事件对象,并调用QObject::event()将其分发出去。

(3)事件对应被分发到当前正在操作的窗口部件上,该窗口部件会调用QWidget::event()函数来处理,然后,在这个函数内部又会调用其他的子函数(如KeyPressEvent或mouseReleaseEvent)来进行具体的处理。

(4)event函数处理完后,可能会将当前事件传递给父组件(parent)对象。但这个过程只是一种可能,也就是有一部分会被传递,有些并不需要被传递。

2. QEvent及其子类对象涉及的关键成员函数:实际上只是在操作或判断一个标志位

(1)void ignore():事件的接收者忽略当前事件,事件可能传递给父组件

(2)void accept();事件的接收者期望处理当前事件,表明我们自己写了事件处理函数,一般不需要被父组件再处理

(3)bool isAccepted();判断当前事件是否被处理

事件传递流程①事件先传递给指定窗口部件,确切的说传递给获得焦点窗口的部件,②如果该部件忽略该事件,那么这个事件就会传递给其父组件
还需要注意当重新实现事件处理函数时,一般需要调用父组件的相应事件处理函数来实现其默认的行为
如:
void MyLineEdit::keyPressEvent(QKeyEvent *e)
{
qDebug()<<"MyLineEdit::keyPressEvent";
    QLineEdit::keyPressEvent(e);// 执行QLineEdit类的默认事件处理
 }

实例事件处理的顺序

//main.cpp

#include "Widget.h"
#include <QApplication> int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show(); return a.exec();
}
/*当在编辑框中按下按键时输出结果:(注意MyLineEdit的父组件,即w中的
的event事件并未被触发
MyLineEdit::event
MyLineEdit::keyPressEvent
*/

//MyLineEdit.h

#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H #include <QLineEdit> class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget* parent = );
bool event(QEvent* e);
void keyPressEvent(QKeyEvent* e);
}; #endif // MYLINEEDIT_H

//MyLineEdit.cpp

#include "MyLineEdit.h"
#include <QKeyEvent>
#include <QDebug> MyLineEdit::MyLineEdit(QWidget* parent):QLineEdit(parent)
{ } bool MyLineEdit::event(QEvent* e)
{
if( e->type() == QEvent::KeyPress)
{
qDebug() << "MyLineEdit::event";
}
return QLineEdit::event(e);
} void MyLineEdit::keyPressEvent(QKeyEvent* e)
{
qDebug() << "MyLineEdit::keyPressEvent";
QLineEdit::keyPressEvent(e); // e->ignore(); //表示事件会继续传递给父组件,本例中为Widget对象
//如果注释或e-accept()表示不再传递,则父组件的
//event函数不会被触发
}

//Widget.h

#ifndef WIDGET_H
#define WIDGET_H #include <QWidget>
#include "MyLineEdit.h" class Widget : public QWidget
{
Q_OBJECT private:
MyLineEdit myLineEdit; public:
Widget(QWidget *parent = ); bool event(QEvent* e);
void keyPressEvent(QKeyEvent* e); ~Widget();
}; #endif // WIDGET_H

//Widget.cpp

#include "Widget.h"
#include <QEvent>
#include <QDebug> Widget::Widget(QWidget *parent)
: QWidget(parent),myLineEdit(this)
{
} //操作系统将消息转化为事件,并分发到了这个Widget,会首先调用
//这个Wiget的event函数,该函数可以收到多种的系统事件,同时其内部会根据event
//事件的类型调用相应的事件处理函数,如keyPressEvent()。比如,当发生按键事件时
//会先调用event(),再调用后面的keyPressEvent()
bool Widget::event(QEvent* e)
{
if(e->type() == QEvent::KeyPress)
{
qDebug() << "Widget::event";
} return QWidget::event(e);
} void Widget::keyPressEvent(QKeyEvent *e)
{
qDebug() << "Widget::keyPressEvent";
QWidget::keyPressEvent(e);
} Widget::~Widget()
{ }

3. Qt中的事件过滤器

(1)事件过滤器

  ①事件过滤器可以对其他组件接收到的事件进行监控

  ②任意的QObject对象都可以作为事件过滤器使用

  ③事件过滤器对象需要重写eventFilter()函数

(2)安装事件过滤器:installEventFilter()函数

  ①事件过滤器在组件之前接收到事件

  ②事件过滤器能够决定是否将事件转到到组件对象

(3)Qt中的事件过滤器与dll中的勾子的不同

  ①Qt中事件的过滤,是由事件的目标对象自己,发起过滤请求的。即委托过滤器,在自己接收事件前,先叫过滤器过滤一下。这意味着目标对象是知道这个过滤器的存在的。如下面例子中的myLineEdit.installEventFilter(this),就是myLineEdit委托Widget对事件进行过滤。

  ②而dll中的勾子不管目标对象愿不愿意,消息都会被拦下,而且目标对象本身也并不知道勾子的存在

(4)事件过滤器的典型实现

//场景:将所有发往obj的事件先经过指定的过滤函数处理一下,然后再发往obj
//返回true表示事件己经处理,无需再传递给obj对象了
//返回false则正常传递到obj对象
bool Widget::eventFilter(QObject* obj, QEvent* e)
{
if(/*根据obj判断是否是所需的目标对象*/)
{
if(/*根据e->type()判断是否是感兴趣的事件*/)
{
/*事件处理逻辑*/
}
} /*调用父类中的同名函数*/
return QWidget::eventFilter(obj, e);
}

main.cpp

#include <QApplication>
#include "widget.h" int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show(); return a.exec();
}

  widget.h

#ifndef WIDGET_H
#define WIDGET_H #include <QWidget>
#include "mylineedit.h" class Widget : public QWidget
{
Q_OBJECT
MyLineEdit* lineEdit;
protected:
void keyPressEvent(QKeyEvent *);
public:
Widget(QWidget *parent = 0);
~Widget();
bool eventFilter(QObject* obj, QEvent *event);
}; #endif // WIDGET_H

  widget.cpp

#include "widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
lineEdit=new MyLineEdit(this);
//安装事件过滤器,即让所有发往myLineEdit的事件先由经由eventFilter过滤,这里委派Widget的EventFilter来过滤
lineEdit->installEventFilter(this);//在Widget上为lineedit安装事件过滤器了
} Widget::~Widget()
{ } bool Widget::eventFilter(QObject *obj, QEvent *event)//事件过滤器
{
//该过滤器只过滤发往myLineEdit对象的KeyPress事件
if(obj==lineEdit)//判断事件的对象是不是linEdit
{
if(event->type()==QEvent::KeyPress)//判断事件类型
{
qDebug()<<"Widget::eventFilter";
}
}
return QWidget::eventFilter(obj, event);//最后返回QWidget类默认的事件过滤器的执行结果
} void Widget::keyPressEvent(QKeyEvent *)
{
  qDebug()<<"Widget::keyPressEvent";
}

mylinedit.h

#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H #include <QLineEdit>
#include <QEvent>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
protected:
void keyPressEvent(QKeyEvent *e); public:
explicit MyLineEdit(QWidget *parent = 0); bool event(QEvent* event);
signals: public slots: }; #endif // MYLINEEDIT_H

  

mylineedit.cpp

#include "mylineedit.h"
#include <QDebug>
#include <QkeyEvent>
#include <QLineEdit>
MyLineEdit::MyLineEdit(QWidget *parent) :
QLineEdit(parent)
{ } bool MyLineEdit::event(QEvent *event)
{
if(event->type()==QEvent::KeyPress)
qDebug()<<"MyLineEdit::event"; return QLineEdit::event(event);//执行QLineEdit类的event()函数的默认操作 因为event()函数是有一个bool型返回值所以在函数的最后要使用return语句,这里一般是返回父类的event()函数的操作结果
} void MyLineEdit::keyPressEvent(QKeyEvent *e)
{
qDebug()<<"MyLineEdit::keyPressEvent"; // QLineEdit::keyPressEvent(e);
e->ignore();
}

  当点击键盘按键时,执行结果为:

Widget::eventFilter
MyLineEdit::event
MyLineEdit::keyPressEvent
Widget::keyPressEvent

可以看到事件的传递顺序是:事件过滤器----->该部件的event()函数------>该部件的事件处理函数------>有可能是父组件的event函数(如果子部件ignore())

3. 小结

(1)Qt应用程序有严格的事件处理顺序

(2)Qt事件在处理后可能传递给父组件对象

(3)可以通过installEventFilter()函数安装事件过滤器

(4)事件过滤器可以对其他组件接收到的事件进行监控

(5)事件过滤器能够决定是否将事件转发到组件对象

Qt 中的事件处理(二)的更多相关文章

  1. Qt 中的事件处理(一)

    1.图形界面应用程序的消息处理模型 特点: 基于操作系统才能运行 GUI应用程序提供的功能必须由用户触发 用户操作界面时操作系统是第一个感知的 系统内核的消息通过事件处理转变成QT的信号 2. Qt中 ...

  2. 第38课 Qt中的事件处理(上)

    1. GUI程序原理回顾 (1)图形界面应用程序的消息处理模型 (2)思考:操作系统发送的消息如何转变为Qt信号 2. Qt中的事件处理 (1)Qt平台将系统产生的消息转换为Qt事件 ①Qt事件是一个 ...

  3. Qt事件系统之一:Qt中的事件处理与传递

    一.简介 在Qt中,事件作为一个对象,继承自 QEvent 类,常见的有键盘事件 QKeyEvent.鼠标事件 QMouseEvent 和定时器事件 QTimerEvent 等,与 QEvent 类的 ...

  4. 第39课 Qt中的事件处理(下)

    1. 事件的传递过程 (1)操作系统检测到用户动作时,会产生一条系统消息,该消息被发送到Qt应用程序 (2)Qt应用程序收到系统消息后,将其转化为一个对应的QEvent事件对象,并调用QObject: ...

  5. OS开发中的事件处理(二)-事件传递,响应者链条

    事件处理的事件传递 简介: 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件 队列中,UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理, ...

  6. QT_8_Qt中的事件处理_定时器事件_定时器类_事件分发器_事件过滤器_绘图事件_高级绘图事件_绘图设备_QFile 文件读写_QFileInfo文件信息

    Qt中的事件处理 1.1. 捕获QLabel中是鼠标事件 1.2. enterevent 鼠标进入 1.3. leaveevent 鼠标离开 1.4. 鼠标按下MyLabel::mousePressE ...

  7. Qt中事件处理的方法(三种处理方法,四种覆盖event函数,notify函数,event过滤,事件处理器。然后继续传递给父窗口。可观察QWidget::event的源码,它是虚拟保护函数,可改写)

    一.Qt中事件处理的方式   1.事件处理模式一 首先是事件源产生事件,最后是事件处理器对这些事件进行处理.然而也许大家会问, Qt中有这么多类的事件,我们怎么样比较简便的处理每个事件呢?设想,如果是 ...

  8. QT开发(十二)——QT事件处理机制

    一.QT事件简介 QT程序是事件驱动的, 程序的每个动作都是由内部某个事件所触发.QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. 常见的QT事件类型如下: 键盘事件: 按键按下和松开 ...

  9. Qt中事件处理的顺序

    本站所有文章由本站和原作者保留一切权力,仅在保留本版权信息.原文链接.原文作者的情况下允许转载,转载请勿删改原文内容, 并不得用于商业用途. 谢谢合作.原文链接:Qt中事件处理的顺序 文章内容主要来自 ...

随机推荐

  1. LeetCode--122、167、169、189、217 Array(Easy)

    122. Best Time to Buy and Sell Stock II Say you have an array for which the ith element is the price ...

  2. pycharm 利用virtualenv为每个项目配置venv

    1.在某个位置安装一个虚拟环境 2.项目运行是配置virtualenv生成的环境 3.重启terminal 安装依赖: exp => pip install django

  3. POJ 2234 Matches Game(Nim博弈裸题)

    Description Here is a simple game. In this game, there are several piles of matches and two players. ...

  4. Mac os fatal error: 'numpy/arrayobject.h' file not found

    $ python setup.py install 出错信息如: clang -fno-strict-aliasing -fno-common -dynamic -g -O2 -DNDEBUG -g ...

  5. Wifi设备接入流程

    这是硬件平台下文档结构图,详细了解戳这里具体了解这里. 什么意思呢?要想实现控制wifi设备,基本流程是: 咱自己的wifi设备----------自己的服务器(指图中的厂商服务器)-------微信 ...

  6. html播放音乐

    如何在网站网页中添加音乐代码 告诉你多种格式文件的详细使用代码.    width_num——指定一个作为宽度的数字:    height_num——指定一个作为高度的数字:     1.mp3    ...

  7. HDU 1087:Super Jumping! Jumping! Jumping!(LIS)

    Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 ...

  8. 09 Collection,Iterator,List,listIterator,Vector,ArrayList,LinkedList,泛型,增强for,可变参数,HashSet,LinkedHashSet,TreeSet

    09 Collection,Iterator,List,listIterator,Vector,ArrayList,LinkedList,泛型,增强for,可变参数,HashSet,LinkedHas ...

  9. django额外参数的传递和url命名

    django额外参数的传递 path方法:path(route, view, kwargs=None, name=None) path方法可以传递入一个额外参数的字典参数(kwarg),字典里的值就会 ...

  10. 容器(container)

    一.容器有哪些 平时我们经常看到各种容器名称:Servlet容器.WEB容器.Java WEB容器.Java EE容器等 二.容器是什么 2-1     容器通常理解就是装东西的,我们这里说技术上的容 ...