当前位置:   article > 正文

从Qt源码看event/event handler/eventFilter_eventfilter源代码

eventfilter源代码

基于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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93

其中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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

然后以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();
}
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

至此,可以得到event/event handler/eventFilter三者的基本脉络:
(1)事件产生并经过层层传递到达QApplicationPrivate::notify_helper
(2)经过QCoreApplication对象的事件过滤(即安装至QCoreApplication单例实例的eventFilter)
(3)设置Qt::WA_UnderMouse属性
(4)经过目标对象的事件过滤
(5)调用目标对象的event函数
(6)在event函数中根据事件类型调用相应的event handler

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/615889
推荐阅读
相关标签
  

闽ICP备14008679号