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;
        ...
}
相关推荐
牵牛老人2 小时前
【Qt上位机与下位机交互数据组装与解析:全类型数据转换实战指南】
开发语言·qt·交互
郝学胜-神的一滴2 小时前
B站:从二次元到AI创新孵化器的华丽转身 | Google Cloud峰会见闻
开发语言·人工智能·算法
新缸中之脑2 小时前
Google:Rust实战评估
开发语言·后端·rust
im_AMBER2 小时前
消失的最后一秒:SSE 流式联调中的“时序竞争”
前端·笔记·学习·http·sse
Engineer邓祥浩2 小时前
设计模式学习(25) 23-23 责任链模式
学习·设计模式·责任链模式
果粒蹬i2 小时前
从割裂到融合:MATLAB与Python混合编程实战指南
开发语言·汇编·python·matlab
生骨大头菜2 小时前
对接金蝶上传附件接口
java·开发语言
skywalker_112 小时前
File:路径详述
java·开发语言·file
2301_790300962 小时前
嵌入式GPU编程
开发语言·c++·算法