赞
踩
基于Qt 5.9.7
通过继承QObject参与到Qt的事件循环,重写QObject::event
在The Event System中提到
When an event occurs, Qt creates an event object to represent it by constructing an instance of the appropriate QEvent subclass, and delivers it to a particular instance of QObject (or one of its subclasses) by calling its event() function.
这里只是笼统说了“When an event occurs”,到底当事件发生时,是谁触发了QObject::event?
答案是QApplication::notify(此处仅讨论窗口程序,不探讨控制台程序),重载了QGuiApplication::notify,QGuiApplication::notify又重载了 QCoreApplication::notify
Sends event to receiver: receiver->event(event). Returns the value that is returned from the receiver’s event handler. Note that this function is called for all events sent to any object in any thread.
至于QCoreApplication::notify之前发生的事情本文不作阐述,可参照Qt 事件处理机制-qt源码解读
文中给出基本的调用过程
1 main(int, char **)
2 QApplication::exec()
3 QCoreApplication::exec()
4 QEventLoop::exec(ProcessEventsFlags )
5 QEventLoop::processEvents(ProcessEventsFlags )
6 QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags)
–
1 QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2 bool QETWidget::translateMouseEvent(const MSG &msg)
3 bool QApplicationPrivate::sendMouseEvent(…)
4 inline bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)
5 bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event)
6 bool QApplication::notify(QObject *receiver, QEvent *e)
7 bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
8 bool QWidget::event(QEvent *event)
————————————————
版权声明:本文为CSDN博主「luckyone906」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011555996/article/details/122071755
C:\Qt\Qt5.9.7\5.9.7\Src\qtbase\src\widgets\kernel\qapplication.cpp
... bool QApplication::notify(QObject *receiver, QEvent *e) { ... //由于nofify函数比较长,此处仅截取其中一部分 bool res = false; if (!receiver->isWidgetType()) { res = d->notify_helper(receiver, e); } else switch (e->type()) { case QEvent::ShortcutOverride: case QEvent::KeyPress: case QEvent::KeyRelease: { bool isWidget = receiver->isWidgetType(); #if QT_CONFIG(graphicsview) const bool isGraphicsWidget = !isWidget && qobject_cast<QGraphicsWidget *>(receiver); #endif QKeyEvent* key = static_cast<QKeyEvent*>(e); bool def = key->isAccepted(); QPointer<QObject> pr = receiver; while (receiver) { if (def) key->accept(); else key->ignore(); QWidget *w = isWidget ? static_cast<QWidget *>(receiver) : 0; #if QT_CONFIG(graphicsview) QGraphicsWidget *gw = isGraphicsWidget ? static_cast<QGraphicsWidget *>(receiver) : 0; #endif res = d->notify_helper(receiver, e); if ((res && key->isAccepted()) || !pr || (isWidget && (w->isWindow() || !w->parentWidget())) #if QT_CONFIG(graphicsview) || (isGraphicsWidget && (gw->isWindow() || !gw->parentWidget())) #endif ) { break; } #if QT_CONFIG(graphicsview) receiver = w ? (QObject *)w->parentWidget() : (QObject *)gw->parentWidget(); #else receiver = w->parentWidget(); #endif } qt_in_tab_key_event = false; } break; ... default: res = d->notify_helper(receiver, e); break; } return res; } bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) { // send to all application event filters if (threadRequiresCoreApplication() && receiver->d_func()->threadData->thread == mainThread() && sendThroughApplicationEventFilters(receiver, e)) return true; if (receiver->isWidgetType()) { QWidget *widget = static_cast<QWidget *>(receiver); #if !defined(QT_NO_CURSOR) // toggle HasMouse widget state on enter and leave if ((e->type() == QEvent::Enter || e->type() == QEvent::DragEnter) && (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == widget->window())) widget->setAttribute(Qt::WA_UnderMouse, true); else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave) widget->setAttribute(Qt::WA_UnderMouse, false); #endif if (QLayout *layout=widget->d_func()->layout) { layout->widgetEvent(e); } } // send to all receiver event filters if (sendThroughObjectEventFilters(receiver, e)) return true; // deliver the event bool consumed = receiver->event(e); //此处调用QObject::event QCoreApplicationPrivate::setEventSpontaneous(e, false); return consumed; }
其中eventFilter在这里调用
C:\Qt\Qt5.9.7\5.9.7\Src\qtbase\src\corelib\kernel\qcoreapplication.cpp
bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, QEvent *event) { if (receiver != QCoreApplication::instance() && receiver->d_func()->extraData) { for (int i = 0; i < receiver->d_func()->extraData->eventFilters.size(); ++i) { QObject *obj = receiver->d_func()->extraData->eventFilters.at(i); if (!obj) continue; if (obj->d_func()->threadData != receiver->d_func()->threadData) { qWarning("QCoreApplication: Object event filter cannot be in a different thread."); continue; } if (obj->eventFilter(receiver, event)) //事件过滤 return true; } } return false; }
然后以QWidget为例看看event handler的调用
C:\Qt\Qt5.9.7\5.9.7\Src\qtbase\src\widgets\kernel\qwidget.cpp
bool QWidget::event(QEvent *event) { ... //由于event函数比较长,此处仅截取其中一部分 switch (event->type()) { case QEvent::MouseMove: mouseMoveEvent((QMouseEvent*)event); break; case QEvent::MouseButtonPress: mousePressEvent((QMouseEvent*)event); break; case QEvent::MouseButtonRelease: mouseReleaseEvent((QMouseEvent*)event); break; case QEvent::MouseButtonDblClick: mouseDoubleClickEvent((QMouseEvent*)event); break; #if QT_CONFIG(wheelevent) case QEvent::Wheel: wheelEvent((QWheelEvent*)event); break; ... default: return QObject::event(event); } return true; } ... void QWidget::mouseMoveEvent(QMouseEvent *event) { event->ignore(); } void QWidget::mouseReleaseEvent(QMouseEvent *event) { event->ignore(); } ...
至此,可以得到event/event handler/eventFilter三者的基本脉络:
(1)事件产生并经过层层传递到达QApplicationPrivate::notify_helper
(2)经过QCoreApplication对象的事件过滤(即安装至QCoreApplication单例实例的eventFilter)
(3)设置Qt::WA_UnderMouse属性
(4)经过目标对象的事件过滤
(5)调用目标对象的event函数
(6)在event函数中根据事件类型调用相应的event handler
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。