QT事件循环机制源码学习

文章目录

QT源码中事件梳理过程中调用函数如下:

1.app.exec(); 开启应用程序的事件循环

cpp 复制代码
    QApplication app(argc, argv);
    return app.exec();

2. int QCoreApplication::exec()

3.使用QEventLoop开启事件循环

cpp 复制代码
    QEventLoop eventLoop;
    self->d_func()->in_exec = true;
    self->d_func()->aboutToQuitEmitted = false;
    int returnCode = eventLoop.exec();

4.bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)

  • QEventDispatcherWin32 是 Qt 框架中事件调度器的一个具体实现,用于 Windows 平台。它是QAbstractEventDispatcher 的子类,负责管理 Qt 应用程序的事件循环在 Windows 上的运行。linux平台是类QEventDispatcherUNIX
  • 负责 Qt 应用程序在 Windows 上的主事件循环
  • 处理 Windows 消息与 Qt 事件的转换和分发
  • 是 QApplication::exec() 在 Windows 上的底层实现
  • 通过打断点也可以看到开启事件循环后程序会持续进入这个函数QEventDispatcherWin32::processEvents
cpp 复制代码
class Q_CORE_EXPORT QEventDispatcherWin32 : public QAbstractEventDispatcher
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(QEventDispatcherWin32)
    
    ......

5.以鼠标点击为例,windows是如何将鼠标点击的系统消息转化到Qt可识别的事件类型

cpp 复制代码
1.extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

2.bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
                                  QtWindows::WindowsEventType et,
                                  WPARAM wParam, LPARAM lParam,
                                  LRESULT *result,
                                  QWindowsWindow **platformWindowPtr)


// 将操作系统打包的事件解包、翻译为QApplication可识别的事件
3.bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
                                               QtWindows::WindowsEventType et,
                                               MSG msg, LRESULT *result)

4.QWindowSystemInterface::handleMouseEvent(window, clientPosition, globalPosition, buttons, m_lastEventButton,
                                                         QEvent::MouseButtonRelease, keyModifiers, source);
                                                         
5.void QWidgetWindow::handleMouseEvent(QMouseEvent *event)

6.bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
                                         QWidget *alienWidget, QWidget *nativeWidget,
                                         QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,
                                         bool spontaneous, bool onlyDispatchEnterLeave)
// 系统鼠标、键盘消息一般都是此接口  
7.QApplication::sendSpontaneousEvent(receiver, event);

8.bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)
{
    Q_TRACE(QCoreApplication_sendSpontaneousEvent, receiver, event, event->type());

    if (event)
        event->spont = true;
    return notifyInternal2(receiver, event);
}

6.bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)

7.bool QCoreApplication::notify(QObject *receiver, QEvent *event)

8.bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)

  • 向事件过滤器发送该事件,这里介绍一下Event Filters. 事件过滤器是一个接受即将发送给目标对象所有事件的对象。
  • 如代码所示它开始处理事件在目标对象行动之前。过滤器的 QObject::eventFilter()实现被调用,能接受或者丢弃过滤
  • 允许或者拒绝事件的更进一步的处理。如果所有的事件过滤器允许更进一步的事件处理,事件将被发送到目标对象本身。
  • 如果他们中的一个停止处理,目标和任何后来的事件过滤器不能看到任何事件。
cpp 复制代码
bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{
    // Note: when adjusting the tracepoints in here
    // consider adjusting QApplicationPrivate::notify_helper too.
    Q_TRACE(QCoreApplication_notify_entry, receiver, event, event->type());
    bool consumed = false;
    bool filtered = false;
    Q_TRACE_EXIT(QCoreApplication_notify_exit, consumed, filtered);

    // send to all application event filters (only does anything in the main thread)
    if (QCoreApplication::self
            && receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread()
            && QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) {
        filtered = true;
        return filtered;
    }
    // 这个函数中会访问receiver(目标对象)的过滤器,判断是否需要过滤此事件,return true就是过滤掉 false则是不过滤会真正传递给receiver(目标对象)
    if (sendThroughObjectEventFilters(receiver, event)) {
        filtered = true;
        return filtered;
    }

 // receiver(目标对象)的事件处理函数被真正得到执行
    consumed = receiver->event(event);
    return consumed;
}

9.事件派发至目标对象QObject的子类,这里以QWidget为例

cpp 复制代码
bool QWidget::event(QEvent *event)
{
    ...
 
    switch (event->type()) {
    case QEvent::MouseMove:
        mouseMoveEvent((QMouseEvent*)event);
        break;
 
    case QEvent::MouseButtonPress:
 #if 0
        resetInputContext();
 #endif
        mousePressEvent((QMouseEvent*)event);
        break;
        ...
}
相关推荐
郑州光合科技余经理3 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
feifeigo1233 天前
matlab画图工具
开发语言·matlab
西岸行者3 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
dustcell.3 天前
haproxy七层代理
java·开发语言·前端
norlan_jame3 天前
C-PHY与D-PHY差异
c语言·开发语言
多恩Stone3 天前
【C++入门扫盲1】C++ 与 Python:类型、编译器/解释器与 CPU 的关系
开发语言·c++·人工智能·python·算法·3d·aigc
QQ4022054963 天前
Python+django+vue3预制菜半成品配菜平台
开发语言·python·django
遥遥江上月3 天前
Node.js + Stagehand + Python 部署
开发语言·python·node.js
悠哉悠哉愿意3 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
m0_531237173 天前
C语言-数组练习进阶
c语言·开发语言·算法