我们知道,用户的操作会被操作系统感知到,然后操作系统会将用户的操作翻译成系统消息,然后这个系统消息经过一系列变化就会变成QT事件对象,那么这样的事件是由操作系统发送过来的。
事件对象的由来不仅仅是由操作系统带来的,我们也可以在程序中自主的发送事件对象,可以发送QT中预定义的事件对象,也可以发送QT中自定义的事件对象。
在一般的GUI开发平台中,存在两种事件发送方式,一种是阻塞型事件发送,另外一种是非阻塞型事件发送。
-阻塞型事件发送:事件发送后需要等待事件处理完成
-非阻塞型事件发送:事件发送后立即返回,事件被发送到事件队列中等待处理。
在QT开发平台下,对这2种事件的表现形式为:
sendEvent(QObject* receiver,QEvent* event) 中事件对象的生命期由QT程序管理,它同时支持栈事件对象和堆事件对象的发送
postEvent(QObject* receiver,QEvent* event) 中事件对象的生命期由Qt平台管理,它只能发送堆事件对象,事件被处理后由Qt平台销毁。
来看一下 sendEvent(QObject* receiver,QEvent* event) 为什么是阻塞型的?
因为在sendEvent(QObject* receiver,QEvent* event)函数内部,直接调用了Qt对象的event()事件处理函数,当event()事件处理函数没有返回时,sendEvent(QObject* receiver,QEvent* event)就肯定不会返回,所以sendEvent()是阻塞型的。
而在postEvent(QObject* receiver,QEvent* event)函数内部,是直接将事件发送到事件队列中去等待处理,然后事件被发送到事件队列中去之后,它就马上返回了,然后事件队列里面的事件就会被分发下去,分发到具体的对应QT对象上去,然后具体的QT对象就会调用自己的event()事件处理函数进行事件处理,所以它不是阻塞型的。
下面用一个程序实例来验证上面的原理。
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
#include <QPushButton>
class Widget : public QWidget
{
Q_OBJECT
private:
QPushButton m_pushButton;
protected slots:
void onButtonClicked();
public:
Widget(QWidget *parent = 0);
void testSendEvent();
void testPostEvent();
bool event(QEvent* evt);
~Widget();
};
#endif // WIDGET_H
#include "Widget.h"
#include <QMouseEvent>
#include <QApplication>
#include <QDebug>
Widget::Widget(QWidget *parent): QWidget(parent)
{
m_pushButton.setParent(this);
m_pushButton.setText("TestButton");
connect(&m_pushButton,SIGNAL(clicked()),this,SLOT(onButtonClicked()));
}
void Widget::onButtonClicked()
{
testSendEvent();
//testPostEvent();
}
void Widget::testSendEvent()
{
QMouseEvent dbcEvt(QEvent::MouseButtonDblClick,QPoint(0,0),Qt::LeftButton,Qt::NoButton,Qt::NoModifier);
qDebug()<<"Before() sendEvent()";
QApplication::sendEvent(this,&dbcEvt);//将一个鼠标的双击事件发送到当前的Widget对象上来
qDebug()<<"After sendEvent()";
}
void Widget::testPostEvent()
{
QMouseEvent* dbcEvt=new QMouseEvent(QEvent::MouseButtonDblClick,QPoint(0,0),Qt::LeftButton,Qt::NoButton,Qt::NoModifier);
qDebug()<<"Before() postEvent()";
QApplication::postEvent(this,dbcEvt);//将一个鼠标的双击事件发送到当前的Widget对象上来
qDebug()<<"After postEvent()";
}
bool Widget::event(QEvent* evt)
{
if(evt->type()==QEvent::MouseButtonDblClick)
{
qDebug()<<"event():"<<evt;
}
return QWidget::event(evt);
}
Widget::~Widget()
{
}
#include <QtGui/QApplication>
#include "Widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
分析上述程序:
因为sendEvent是阻塞型的,所以在打印出Before() sendEvent()之后,会去调用event()事件处理函数,等event()函数处理完成之后,才会打印After sendEvent()。
接下来看postEvent()的非阻塞型。
因为postEvent是非阻塞型的,然后它发送的事件会将它发送到事件队列中去,然后最后事件队列中的事件将会把他们分发给对应的QT对象进行处理,所以打印的结果才会最后调用bool event(QEvent* evt)这个函数。