基于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