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;
        ...
}
相关推荐
lizhihai_991 分钟前
股市学习心得—半导体12种核心材料
大数据·人工智能·学习
老陈说编程21 分钟前
12. LangChain 6大核心调用方法:invoke/stream/batch同步异步全解析,新手也能轻松学会
开发语言·人工智能·python·深度学习·机器学习·ai·langchain
sakiko_29 分钟前
UIKit学习笔记3-布局、滚动视图、隐藏或显示视图
前端·笔记·学习·objective-c·swift·uikit
014-code30 分钟前
Java 并发中的原子类
java·开发语言·并发
alphageek832 分钟前
Matlab linspace函数完全指南:从基础用法到进阶技巧
开发语言·其他·matlab
AI人工智能+电脑小能手32 分钟前
【大白话说Java面试题】【Java基础篇】第29题:静态代理和动态代理的区别是什么
java·开发语言·后端·面试·代理模式
善恶怪客33 分钟前
Java-数组和可变参数
java·开发语言
谭欣辰39 分钟前
LCS(最长公共子序列)详解
开发语言·c++·算法
RPGMZ1 小时前
RPGMakerMZ 地图存档点制作 标题继续游戏直接读取存档
开发语言·javascript·游戏·游戏引擎·rpgmz·rpgmakermz
丑八怪大丑1 小时前
JDK8-17新特性
java·开发语言