qt源码解析1--事件循环原理(重写事件函数,事件过滤器等)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了qt源码解析1--事件循环原理(重写事件函数,事件过滤器等)相关的知识,希望对你有一定的参考价值。


首先看我上篇博客准备好环境:

​​qt源码解析0--源码获取与环境准备​​


现在进入主题。

先说答案:

  • 事件event默认状态是不确定的,我们可以在处理函数里调用setAccept()或者ignore()函数来改变这个状态
  • 安装事件过滤器时,eventFilter(receiver, event))函数返回true,则目标对象的event()函数得不到执行了。
  • 重写事件函数event()时,函数返回true,而且事件是接收状态,则事件不会继续往父对象传递了,否则会传递给父对象。 注:有些特定事件是否传递给父对象不依赖于返回值,而是依赖与这个接收者类型,以及属性。比如鼠标移动事件 QEvent::MouseMove if (w-
• >isWindow() || w->testAttribute(Qt::WA_NoMousePropagation))
break;

因为qt源码的代码是这也写的:

eventAccepted = (w == receiver ? mouse : &me)->isAccepted();
if (res && eventAccepted)
break;
w = w->parentWidget(); //不断寻找父窗口对象继续传递事件

源码详情,见我下面的图,就清楚了。
 


qt事件循环和处理过程(我跟踪源码得到的)如下图所示:

qt源码解析1--事件循环原理(重写事件函数,事件过滤器等)_事件循环

 

threadData:记录自己线程上的事件派发器(eventDispatcher)、事件队列、对象列表等信息。是独一份的,每个派发器,派发对象它们都有它的指针

QApplication::exec()
QGuiApplication::exec();
QCoreApplication::exec();
QEventLoop eventLoop;
eventLoop.exec();
eventLoop.processEvents(flags | WaitForMoreEvents | EventLoopExec);
threadData->eventDispatcher.load()->processEvents(flags);
//eventDispatcher是基类指针,子类化的有QEventDispatcherWin32、QEventDispatcherBlackberry、QEventDispatcherUNIX等
//这个是在函数QCoreApplicationPrivate::createEventDispatcher()里面根据平台宏定义来创建的QEventDispatcherWin32::createInternalHwnd()
//创建一个windows系统的隐形窗口,用于接收windows系统所有派发事件static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatcher)
//里面为它注册了一个叫做qt_internal_proc的WNDPROC函数QEventDispatcherWin32::installMessageHook()
//注册系统钩子qt_GetMessageHook函数,截获操作系统系统所有事件(注意:这个钩子函数是在操作系统自己的线程执行的)while(canWait)
反复查询PeekMessage(&msg, 0, 0, 0, PM_REMOVE)的消息(这个就是上面钩子函数截获的消息)
相应放入用户输入事件的队列 queuedUserInputEvents
相应放入用户输入事件的队列 queuedSocketEvents
canWait = (!retVal && !d->interrupt && (flags & QEventLoop::WaitForMoreEvents));
//如果消息处理完了,则阻塞自己,等到操作系统有消息发送过来,才会继续往下执行
MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp)
//由于这个函数是在操作系统线程里执行的???所以要尽量的快消息是PM_REMOVE,则
PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0);
//通过PostMessage()函数将事件发送到那个隐形窗口对来处理,对象窗口专门处理LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
//处理上面说的隐形窗口的消息QWindowsGuiEventDispatcher::sendPostedEvents()
QEventDispatcherWin32::sendPostedEvents();
QWindowSystemInterface::sendWindowSystemEvents(m_flags);
QGuiApplicationPrivate::processWindowSystemEvent(event);
QGuiApplicationPrivate::processWheelEvent(static_cast<QWindowSystemInterfacePrivate::WheelEvent *>(e));
QGuiApplicationPrivate::processMouseEvent(static_cast<QWindowSystemInterfacePrivate::MouseEvent *>(e));
QGuiApplication::sendSpontaneousEvent(window, &ev);
notifyInternal2(receiver, event)
QCoreApplication::notify(QObject *receiver, QEvent *event)
//这个是虚函数,会对应到子类的具体函数,一般是QApplication::notify
bool eventAccepted = mouse->isAccepted(); //也就是事件默认是接收状态
QPointer<QWidget> pw = w;while (w)
res = d->notify_helper(w, w == receiver ? mouse : &me);
// 这里让事件过滤器先执行了
if (sendThroughObjectEventFilters(receiver, e))
return true; // 遍历安装到receiver的事件过滤器对象们,先让它们的eventFilter()函数执行
for (int i = 0; i < receiver->d_func()->extraData->eventFilters.size(); ++i)
if (obj->eventFilter(receiver, event)) //这儿就是我们熟悉的事件过滤器函数了
return true;// deliver the event
bool consumed = receiver->event(e); //这儿就是我们熟悉的可以重写的事件处理函数了//这里以继承Qobject的Qwidget为例:
bool QWidget::event(QEvent *event)
switch (event->type())
case QEvent::MouseMove:
mouseMoveEvent((QMouseEvent*)event);
break; case QEvent::MouseButtonPress:
mousePressEvent((QMouseEvent*)event);
break;。。。
QCoreApplicationPrivate::setEventSpontaneous(e, false);
return consumed;eventAccepted = (w == receiver ? mouse : &me)->isAccepted();
if (res && eventAccepted)
break;
w = w->parentWidget(); //不断寻找父窗口对象

以上是关于qt源码解析1--事件循环原理(重写事件函数,事件过滤器等)的主要内容,如果未能解决你的问题,请参考以下文章

Qt源码阅读 事件循环

qt中重写键盘事件冲突了

Qt信号槽机制源码解析

Qt文档阅读笔记-void QObject::deleteLater()解析

Qt文档阅读笔记-void QObject::deleteLater()解析

QT中的线程与事件循环理解