QT程序是事件驱动的, 程序的每一个动做都是由内部某个事件所触发。QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期。异步
常见的QT事件类型以下:函数
键盘事件: 按键按下和松开post
鼠标事件: 鼠标移动,鼠标按键的按下和松开this
拖放事件: 用鼠标进行拖放spa
滚轮事件: 鼠标滚轮滚动操作系统
绘屏事件: 重绘屏幕的某些部分指针
定时事件: 定时器到时code
焦点事件: 键盘焦点移动对象
进入和离开事件: 鼠标移入widget以内,或是移出blog
移动事件: widget的位置改变
大小改变事件: widget的大小改变
显示和隐藏事件: widget显示和隐藏
窗口事件: 窗口是否为当前窗口
QT将系统产生的消息转化为QT事件,QT事件被封装为对象,全部的QT事件均继承抽象类QEvent,用于描述程序内部或外部发生的动做,任意的QObject对象都具有处理QT事件的能力。
操做系统将获取的事件,好比鼠标按键,键盘按键等keyPressEvent,keyReleaseEvent,mousePressEvent,mouseReleaseEvent事件, 放入系统的消息队列中,Qt事件循环的时候读取消息队列中的消息,转化为QEvent并被分发到相应的QWidget对象,相应的QWidget中的event(QEvent *)进行事件处理会对事件进行处理,event(QEvent *)会根据事件类型调用不一样的事件处理函数,在事件处理函数中发送QT预约义的信号,最终调用信号关联的槽函数。
GUI应用程序的事件处理:
A、QT事件产生后会被当即发送到相应的QWidget对象
B、相应的QWidget中的event(QEvent *)进行事件处理
C、event(QEvent *)根据事件类型调用不一样的事件处理函数
D、在事件处理函数中发送QT预约义的信号
E、调用信号关联的槽函数
程序产生事件有两种方式, 一种是调用QApplication::postEvent(), 例如QWidget::update()函数,当须要从新绘制屏幕时,程序调用update()函数,new出来一个paintEvent,调用 QApplication::postEvent(),将其放入Qt的消息队列中,等待依次被处理;
另外一种方式是调用sendEvent()函数,事件不会放入队列, 而是直接被派发和处理, QWidget::repaint()函数用的就是阻塞型的。
sendEvent()中事件对象的生命期由Qt程序管理,支持分配在栈上和堆上的事件对象;postEvent()中事件对象的生命期由Qt平台管理,只支持分配在堆上的事件对象,事件被处理后由Qt平台销毁。
事件有两种调度方式,同步和异步。
Qt的事件循环是异步的,当调用QApplication::exec()时,就进入了事件循环,先处理Qt事件队列中的事件, 直至为空,再处理系统消息队列中的消息, 直至为空, 处理系统消息的时候会产生新的Qt事件, 须要对其再次进行处理。
调用QApplication::sendEvent的时候, 消息会当即被处理,是同步的。实际上QApplication::sendEvent()是经过调用QApplication::notify(), 直接进入了事件的派发和处理环节。
事件过滤器是Qt中一个独特的事件处理机制, 功能强大并且使用起来灵活方便。经过事件过滤器, 可让一个对象侦听拦截另一个对象的事件。事件过滤器实现以下: 在全部Qt对象的基类QObject中有一个类型为QObjectList的成员变量,名字为eventFilters,当某个QObject(A)给另外一个QObject(B)安装了事件过滤器后, B会把A的指针保存在eventFilters中。在B处理事件前,会先去检查eventFilters列表, 若是非空, 就先调用列表中对象的eventFilter()函数。一个对象能够给多个对象安装过滤器,一个对象能同时被安装多个过滤器, 在事件到达以后, 事件过滤器以安装次序的反序被调用。事件过滤器函数( eventFilter() ) 返回值是bool型, 若是返回true, 则表示事件已经被处理完毕, Qt将直接返回, 进行下一事件的处理。若是返回false, 事件将接着被送往剩下的事件过滤器或是目标对象进行处理。
QT中,事件的派发是从 QApplication::notify()开始的, 由于QAppliction也是继承自QObject, 因此先检查QAppliation对象, 若是有事件过滤器安装在qApp上, 先调用事件过滤器,接下来QApplication::notify() 会过滤或合并一些事件(好比失效widget的鼠标事件会被过滤掉, 而同一区域重复的绘图事件会被合并),事件被送到reciver::event()处理。
在reciver::event()中, 先检查有无事件过滤器安装在reciever上。如有, 则调用之。而后根据QEvent的类型, 调用相应的特定事件处理函数。常见的事件都有特定事件处理函数, 好比:mousePressEvent(), focusOutEvent(), resizeEvent(), paintEvent(), resizeEvent()等等。在实际应用中, 常常须要重载特定事件处理函数处理事件。对于不常见的事件, 没有相对应的特定事件处理函数,若是要处理这些事件, 就须要使用别的办法, 好比重载event() 函数, 或是安装事件过滤器。
对于某些类别的事件,若是在整个事件的派发过程结束后尚未被处理, 那么这个事件将会向上转发给它的父widget, 直到最顶层窗口。Qt中和事件相关的函数经过两种方式相互通讯,一种是QApplication::notify(), QObject::eventFilter(), QObject::event()经过返回bool值来表示是否已处理;另外一种是调用QEvent::ignore() 或 QEvent::accept() 对事件进行标识,只用于event()函数和特定事件处理函数之间的沟通,并且只有用在某些类别事件上是有意义的, 这些事件就是上面提到的那些会被转发的事件, 包括: 鼠标, 滚轮, 按键等事件。
QT提供了五种不一样级别的事件处理和过滤:
A、重写特定事件处理函数.
最多见的事件处理办法就是重写mousePressEvent(), keyPressEvent(), paintEvent() 等特定事件处理函数。
B、重写event()函数.
重写event()函数时, 须要调用父类的event()函数来处理不须要处理或是不清楚如何处理的事件。
return QWidget::event(event);
C、在Qt对象上安装事件过滤器
安装事件过滤器有两个步骤: (假设要用A来监视过滤B的事件)
首先调用B的installEventFilter( const QOject *obj ), 以A的指针做为参数,全部发往B的事件都将先由A的eventFilter()处理。而后, A要重写QObject::eventFilter()函数, 在eventFilter() 中对事件进行处理。
D、给QAppliction对象安装事件过滤器
若是给QApplication对象装上过滤器,那么全部的事件在发往任何其余的过滤器时,都要先通过当前eventFilter()。在QApplication::notify() 中, 是先调用qApp的过滤器, 再对事件进行分析, 以决定是否合并或丢弃。
E、继承QApplication类,并重载notify()函数
Qt是用QApplication::notify()函数来分发事件的,要在任何事件过滤器查看任何事件以前先获得这些事件,重写notify()函数是惟一的办法。一般来讲事件过滤器更好用一些, 由于不须要去继承QApplication类,并且能够给QApplication对象安装任意个数的事件过滤器。
class DefineEvent : public QEvent { public: const static QEvent::Type DefineType = static_cast<QEvent::Type>(QEvent::User + 0xFF); explicit DefineEvent(QString data) : QEvent(DefineType) { m_data = data; } QString data() {return m_data;} private: QString m_data; };
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QLineEdit> #include "StringEvent.h" #include <QMouseEvent> #include <QDebug> #include <QApplication> class Widget : public QWidget { Q_OBJECT QLineEdit m_edit; public: Widget(QWidget *parent = 0): QWidget(parent), m_edit(this) { m_edit.installEventFilter(this); } bool event(QEvent* evt) { if( evt->type() == QMouseEvent::MouseButtonDblClick ) { qDebug() << "event: Before sentEvent"; StringEvent e("D.T.Software"); QApplication::sendEvent(&m_edit, &e); qDebug() << "event: After sentEvent"; } return QWidget::event(evt); } bool eventFilter(QObject* obj, QEvent* evt) { if( (obj == &m_edit) && (evt->type() == StringEvent::TYPE) ) { StringEvent* se = dynamic_cast<StringEvent*>(evt); qDebug() << "Receive: " << se->data(); m_edit.insert(se->data()); return true; } return QWidget::eventFilter(obj, evt); } ~Widget() { } }; #endif // WIDGET_H
补充:自定义事件类型可使用registerEventType
QEvent::Type ImageLoadedEvent::evType(){if(s_evType == QEvent::None){s_evType = (QEvent::Type)registerEventType();}return s_evType;}