转自:http://mobile.51cto.com/symbian-272816.htm

在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent. 接下来依次谈谈Qt中有谁来产生、分发、接受和处理事件。

继续我们上一篇文章继续介绍,Qt 事件处理机制 (上篇) 介绍了Qt框架的事件处理机制:事件的产生、分发、接受和处理,并以视窗系统鼠标点击QWidget为例,对代码进行了剖析,向大家分析了Qt框架如何通过Event Loop处理进入处理消息队列循环,如何一步一步委派给平台相关的函数获取、打包用户输入事件交给视窗系统处理,函数调用栈如下:

 main(int, char **)
QApplication::exec()
QCoreApplication::exec()
QEventLoop::exec(ProcessEventsFlags )
QEventLoop::processEvents(ProcessEventsFlags )
QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags)

本文将介绍Qt app在视窗系统回调后,事件又是怎么一步步通过QApplication分发给最终事件的接受和处理者QWidget::event, (QWidget继承Object,重载其虚函数event),以下所有的讨论都将嵌入在源码之中。

 QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) bool QETWidget::translateMouseEvent(const MSG &msg)
bool QApplicationPrivate::sendMouseEvent(...)
inline bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)
bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
bool QApplication::notify(QObject *receiver, QEvent *e)
bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
bool QWidget::event(QEvent *event) // (续上文Section 7) Section 2-1:
QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
...
//检查message是否属于Qt可转义的鼠标事件
if (qt_is_translatable_mouse_event(message)) {
if (QApplication::activePopupWidget() != ) {
POINT curPos = msg.pt;
//取得鼠标点击坐标所在的QWidget指针,它指向我们在main创建的widget实例
QWidget* w = QApplication::widgetAt(curPos.x, curPos.y);
if (w)
widget = (QETWidget*)w;
}
if (!qt_tabletChokeMouse) {
//对,就在这里。Windows的回调函数将鼠标事件分发回给了Qt Widget
// => Section 2-2
result = widget->translateMouseEvent(msg);
...
}
// Section 2-2 $QTDIR\src\gui\kernel\qapplication_win.cpp
//该函数所在与Windows平台相关,主要职责就是把已windows格式打包的鼠标事件解包、翻译成QApplication可识别的QMouseEvent,QWidget.
bool QETWidget::translateMouseEvent(const MSG &msg)
{
//.. 这里很长的代码给以忽略
// 让我们看一下sendMouseEvent的声明
// widget是事件的接受者; e是封装好的QMouseEvent
// ==> Section 2-3
res = QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down, qt_last_mouse_receiver);
}
// Section 2-3 $QTDIR\src\gui\kernel\qapplication.cpp
bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
QWidget *alienWidget, QWidget *nativeWidget,
QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,
bool spontaneous)
{
//至此与平台相关代码处理完毕
//MouseEvent默认的发送方式是spontaneous, 所以将执行sendSpontaneousEvent。 sendSpontaneousEvent() 与 sendEvent的代码实现几乎相同,
除了将QEvent的属性spontaneous标记不同。 这里是解释什么spontaneous事件:如果事件由应用程序之外产生的,比如一个系统事件。
显然MousePress事件是由视窗系统产生的一个的事件(详见上文Section ~ Section ),因此它是 spontaneous事件 if (spontaneous)
result = QApplication::sendSpontaneousEvent(receiver, event); ==〉Section -
else
result = QApplication::sendEvent(receiver, event);
} // Section 2-4 C:\Qt\4.7.1-Vs\src\corelib\kernel\qcoreapplication.h
inline bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)
{
//将event标记为自发事件
//进一步调用 2-5 QCoreApplication::notifyInternal
if (event) event->spont = true; return self ? self->notifyInternal(receiver, event) : false;
}
// Section 2-5: $QTDIR\gui\kernel\qapplication.cpp
bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
{ // 几行代码对于Qt Jambi (QT Java绑定版本) 和QSA (QT Script for Application)的支持
...
// 以下代码主要意图为Qt强制事件只能够发送给当前线程里的对象,也就是说receiver->d_func()->threadData应该等于QThreadData::current()。
注意,跨线程的事件需要借助Event Loop来派发
QObjectPrivate *d = receiver->d_func();
QThreadData *threadData = d->threadData;
++threadData->loopLevel;
bool returnValue;
QT_TRY {
//哇,终于来到大名鼎鼎的函数QCoreApplication::nofity()了 ==> Section 2-6
returnValue = notify(receiver, event);
} QT_CATCH (...) {
--threadData->loopLevel;
QT_RETHROW;
}
}
// Section 2-6: $QTDIR\gui\kernel\qapplication.cpp
// QCoreApplication::notify和它的重载函数QApplication::notify在Qt的派发过程中起到核心的作用,Qt的官方文档时这样说的:
任何线程的任何对象的所有事件在发送时都会调用notify函数。
bool QApplication::notify(QObject *receiver, QEvent *e)
{
//代码很长,最主要的是一个大大的Switch,Case
..
switch ( e->type())
{
...
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
...
//让自己私有类(d是私有类的句柄)来进一步处理 ==> Section 2-7
res = d->notify_helper(w, w == receiver ? mouse : &me);
e->spont = false;
break;
}
...
}
// Section 2-7: $QTDIR\gui\kernel\qapplication.cpp
bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
{
...
// 向事件过滤器发送该事件,这里介绍一下Event Filters. 事件过滤器是一个接受即将发送给目标对象所有事件的对象。
//如代码所示它开始处理事件在目标对象行动之前。过滤器的QObject::eventFilter()实现被调用,能接受或者丢弃过滤,
允许或者拒绝事件的更进一步的处理。如果所有的事件过滤器允许更进一步的事件处理,事件将被发送到目标对象本身。
如果他们中的一个停止处理,目标和任何后来的事件过滤器不能看到任何事件。
if (sendThroughObjectEventFilters(receiver, e))
return true;
// 递交事件给receiver => Section 2-8
bool consumed = receiver->event(e);
e->spont = false;
}
// Section 2-8 $QTDIR\gui\kernel\qwidget.cpp
// QApplication通过notify及其私有类notify_helper,将事件最终派发给了QObject的子类- QWidget.
bool QWidget::event(QEvent *event)
{
...
switch(event->type()) {
case QEvent::MouseButtonPress:
// Don't reset input context here. Whether reset or not is
// a responsibility of input method. reset() will be
// called by mouseHandler() of input method if necessary
// via mousePressEvent() of text widgets.
#if 0
resetInputContext();
#endif
//mousePressEvent是虚函数,QWidget的子类可以通过重载重新定义mousePress事件的行为
mousePressEvent((QMouseEvent*)event);
break;
}

【转】Qt 事件处理机制 (下篇)的更多相关文章

  1. Qt 事件处理机制 (下篇)

    继续我们上一篇文章继续介绍,Qt 事件处理机制 (上篇) 介绍了Qt框架的事件处理机制:事件的产生.分发.接受和处理,并以视窗系统鼠标点击QWidget为例,对代码进行了剖析,向大家分析了Qt框架如何 ...

  2. Qt 事件处理机制 (上篇)

    本篇来介绍Qt 事件处理机制 .深入了解事件处理系统对于每个学习Qt人来说非常重要,可以说,Qt是以事件驱动的UI工具集. 大家熟知Signals/Slots在多线程的实现也依赖于Qt的事件处理机制. ...

  3. Qt事件处理机制

    研一的时候开始使用Qt,感觉用Qt开发图形界面比MFC的一套框架来方便的多.后来由于项目的需要,也没有再接触Qt了.现在要重新拾起来,于是要从基础学起. Now,开始学习Qt事件处理机制. 先给出原文 ...

  4. 【转】解读Qt 事件处理机制(上篇)

    [转自]:http://mobile.51cto.com/symbian-272812.htm 在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent. 接下来依次谈谈Qt中有谁来产生 ...

  5. 9、Qt 事件处理机制

    原文地址:http://mobile.51cto.com/symbian-272812.htm 在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent. 接下来依次谈谈Qt中有谁来产生 ...

  6. Qt 事件处理机制

    Qt 事件处理机制 因为这篇文章写得特别好,将Qt的事件处理机制能够阐述的清晰有条理,并且便于学习.于是就装载过来了(本文做了排版,并删减了一些冗余的东西,希望原主勿怪),以供学习之用. 简介 在Qt ...

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

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

  8. 【QT学习】QT事件处理机制

    GUI应用程序由 事件驱动. 键盘.鼠标.拖放.滚动.绘屏.定时事件. connect

  9. Qt之事件处理机制

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

随机推荐

  1. Linux的时钟管理

    本文转自博客园zhenwenxian的Linux时间管理,很详细,写得很不错,对初学者还是有很大帮助的. 时间管理在内核中占有非常重要的地位.相对于事件驱动,内核中有大量的函数都是基于时间驱动的.内核 ...

  2. ShapeDrawable 资源

    ShapeDrawable 用于定义一个基本的几何图形(如矩形.圆形.线条等),定义 ShapeDrawable 的 XML 文件的根元素是<shape.../>元素,该元素可指定如下属性 ...

  3. POJ Stockbroker Grapevine 1125 多源最短路(Floyd)

    题目大意: 股票经纪人要散播股票的谣言,每个人都有人际关系,每个人只信任他相信的人传播的谣言, 其实也就是有向图.问 哪个人能最快的将谣言传播给所有人,并且求出传过去的最短时间. 题目分析: 我们用F ...

  4. HBase MemStoreFlusher

    HBase MemStore Flush由类org.apache.hadoop.hbase.regionserver.MemStoreFlusher实现,具体表现为HRegionServer中的一个实 ...

  5. python模块管理

    参考python的模块管理,请看如下 http://blog.sina.com.cn/s/blog_90bc5fc6010159e0.html http://hi.baidu.com/billsche ...

  6. DLL入门浅析(4)——从DLL中导出类

    转载自:http://www.cppblog.com/suiaiguo/archive/2009/07/20/90663.html 前面介绍了怎么从DLL中导出函数和变量,实际上导出类的方法也是大同小 ...

  7. 微博广告推荐中有关Hadoop的那些事

    一.背景 微博,一个DAU上亿.每日发博量几千万的社交性产品,拥有庞大的数据集.如何高效得从如此规模的数据集中挖掘出有价值的信息,以增强用户粘性,提高信息传播速度,就成了重中之重.因此,我们引入了ha ...

  8. Linux2.6内核--VFS层中和进程相关的数据结构

          系统中的每一个进程都有自己的一组打开的文件,像根文件系统,当前工作目录,安装点等.有三个数据结构将 VFS 层和系统的进程紧密的联系在一起,它们分别是: file_struct,fs_st ...

  9. 关于xcode7编译旧项目崩溃-[UIApplication _runWithMainScene:transitionContext:completion:]

    崩溃原因 crash: Assertion failure in -[UIApplication _runWithMainScene:transitionContext:completion:], / ...

  10. JavaScript中判断对象类型的种种方法

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...