Qt事件循环调用过程

事件循环

事件循环是用于处理和调度应用程序中各种异步事件的机制,负责接收和分发事件队列中的各种事件,当GUI程序的事件循环开启后,它便一直在循环处理事件队列中的事件,直到满足条件退出循环,便不再处理事件队列中的事件。

Qt事件循环

Qt的事件循环是Qt作为gui框架的核心,它提供一系列事件处理逻辑,使用户可以通过安装事件过滤器、重写各种event函数,让每个组件对各种封装好的事件进行自定义处理。比起原生窗口过程响应速度,Qt的事件要慢一些,但它给开发人员提供了灵活便捷的事件处理方法。

除了便于事件处理,还可以从另一个角度看待事件循环。熟悉QWidget就会知道,QWidget对象在主线程外的线程操作很容易导致崩溃。而每一个可见的QWidget都会注册一个qWindowsWndProc窗口过程函数,用来处理系统消息,当用户操作鼠标键盘产生消息时。qWindowsWndProc回调并封装该消息成为QEvent,将封装的QEvent添加到事件循环处理的事件队列,再由事件循环去分发事件。
乍一看这种方式是绕了一圈,还增加了事件处理延迟,但背后有两个原因,至少目前笔者是这个认为:1、不能直接在qWindowsWndProc封装好QEvent后直接处理,是因为在非主线程操作可能引起崩溃,QWidget是线程不安全的。2、事件循环是Qt的核心,除了gui还会处理socket、timer事件,因此将QEvent放进事件队列,再让事件循环处理,本质上是一种解耦。

如果上面的话对你有些许帮助,后面的可能不用看了,因为下面主要是笔者记录的一系列调用过程,主要从事件具体在什么地方产生、什么地方封装、什么地方处理进行的记录。

Qt事件循环调用过程

Qt源码版本:5.15.2

事件循环通过QGuiApplication::exec()启动,最终调用到QEventLoop::exec,该函数以while循环调用QEventLoop::processEvents,结束条件是QEventLoopPrivate.exit.loadAcquire()。最终QEventLoopPrivate.threadData.eventDispatcher.processEvents() 进行事件处理。

int QGuiApplication::exec()
{
#ifndef QT_NO_ACCESSIBILITY
    QAccessible::setRootObject(qApp);
#endif
    return QCoreApplication::exec();
}

↓

int QCoreApplication::exec()
{
	//*********************************省略代码
    QEventLoop eventLoop;
    int returnCode = eventLoop.exec();
	//*********************************省略代码
}

↓

int QEventLoop::exec(ProcessEventsFlags flags)
{
	//*********************************省略代码
    while (!d->exit.loadAcquire())
        processEvents(flags | WaitForMoreEvents | EventLoopExec);
	//*********************************省略代码
}

↓
  
bool QEventLoop::processEvents(ProcessEventsFlags flags)
{
    Q_D(QEventLoop);
    auto threadData = d->threadData.loadRelaxed();
    if (!threadData->hasEventDispatcher())
        return false;
    return threadData->eventDispatcher.loadRelaxed()->processEvents(flags);
}//至此事件循环启动完毕,threadData中的eventDispatcher在windows平台下是QWindowsGuiEventDispatcher类

窗口函数注册(消息的来源):

qt_internal_proc //每个Application只有一个该窗口处理函数,通过该窗口过程函数,处理发给该窗口的 WM_QT_SOCKETNOTIFIER、WM_QT_ACTIVATENOTIFIERS、WM_TIMER、WM_QT_SENDPOSTEDEVENTS 类型消息。

qt_internal_proc处理过程:

LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
	//*********************************省略代码
    switch (message) {
    case WM_QT_SOCKETNOTIFIER: {
		//*********************************省略代码
    }
    case WM_QT_ACTIVATENOTIFIERS: {
		//*********************************省略代码
    }
    case WM_TIMER:
		//*********************************省略代码
    case WM_QT_SENDPOSTEDEVENTS:
		//*********************************省略代码
        q->sendPostedEvents();
    }
    //*********************************省略代码
}

参考注册调用栈:

qt_internal_proc                              			qeventdispatcher_win.cpp        
qt_create_internal_window                     			qeventdispatcher_win.cpp       
QEventDispatcherWin32::createInternalHwnd     			qeventdispatcher_win.cpp       
QEventDispatcherWin32::QEventDispatcherWin32  			qeventdispatcher_win.cpp       
QWindowsGuiEventDispatcher::QWindowsGuiEventDispatcher 	qwindowsguieventdispatcher.cpp 
QWindowsIntegration::createEventDispatcher             	qwindowsintegration.cpp 
QGuiApplicationPrivate::createEventDispatcher          	qguiapplication.cpp     
QApplicationPrivate::createEventDispatcher             	qapplication.cpp         
QCoreApplicationPrivate::init                          	qcoreapplication.cpp    
QGuiApplicationPrivate::init                           	qguiapplication.cpp    
QApplicationPrivate::init                              	qapplication.cpp         
QApplication::QApplication                             	qapplication.cpp         

qWindowsWndProc //每个QWidget都有该窗口处理函数,通过该窗口过程函数,封装事件

qWindowsWndProc 处理过程:

extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    //*********************************省略代码
    const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result, &platformWindow);
    //*********************************省略代码
}

参考注册调用栈:

qWindowsWndProc                           				qwindowscontext.cpp     
WindowCreationData::create                				qwindowswindow.cpp      
QWindowsWindowData::create                				qwindowswindow.cpp      
QWindowsIntegration::createPlatformWindow 				qwindowsintegration.cpp 
QWindowPrivate::create                    				qwindow.cpp            
QWindow::create                          				qwindow.cpp                   

事件的封装(事件的来源):

过程:
extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    //*********************************省略代码
    const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result, &platformWindow);
    //*********************************省略代码
}

↓

bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
                                  QtWindows::WindowsEventType et,
                                  WPARAM wParam, LPARAM lParam,
                                  LRESULT *result,
                                  QWindowsWindow **platformWindowPtr)
{
    //*********************************省略代码
    case QtWindows::MouseWheelEvent:
    case QtWindows::MouseEvent:
    case QtWindows::LeaveEvent:
        {
            QWindow *window = platformWindow->window();
            while (window && (window->flags() & Qt::WindowTransparentForInput))
                window = window->parent();
            if (!window)
                return false;
            if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
                return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result);
            else
                return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
        }
        break;
    //*********************************省略代码
}

↓

bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
                                                 HWND hwnd,
                                                 QtWindows::WindowsEventType et,
                                                 MSG msg,
                                                 LRESULT *result)
{
    //*********************************省略代码
    if (et == QtWindows::MouseWheelEvent)
        return translateMouseWheelEvent(window, currentWindowUnderPointer, msg, globalPos, keyModifiers);
    //*********************************省略代码
}

↓

bool QWindowsPointerHandler::translateMouseWheelEvent(QWindow *window,
                                                      QWindow *currentWindowUnderPointer,
                                                      MSG msg,
                                                      QPoint globalPos,
                                                      Qt::KeyboardModifiers keyModifiers)
{
    //*********************************省略代码
    QWindowSystemInterface::handleWheelEvent(receiver, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
    //*********************************省略代码
}

↓

//创建/封装事件
bool QWindowSystemInterface::handleWheelEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase,
                                              Qt::MouseEventSource source, bool invertedScrolling)
{
    //*********************************省略代码
        e = new QWindowSystemInterfacePrivate::WheelEvent(window, timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativePixels(global, window), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical,
                                                          mods, phase, source, invertedScrolling);

        return QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
    //*********************************省略代码
}

↓

//将封装好的事件添加进windowSystemEventQueue
template<>
bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterface::AsynchronousDelivery>(WindowSystemEvent *ev)
{
    windowSystemEventQueue.append(ev);
    if (QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::qt_qpa_core_dispatcher())
        dispatcher->wakeUp();
    return true;
}

参考事件封装调用栈:

QEventDispatcherWin32::processEvents      				qeventdispatcher_win.cpp       
QWindowsGuiEventDispatcher::processEvents 				qwindowsguieventdispatcher.cpp 
QEventLoop::processEvents                 				qeventloop.cpp                
QEventLoop::exec                          				qeventloop.cpp               
QCoreApplication::exec                    				qcoreapplication.cpp      
QGuiApplication::exec                     				qguiapplication.cpp     
QApplication::exec                        				qapplication.cpp           

事件的分发(事件的处理):

过程:
void QEventDispatcherWin32::wakeUp()
{
    //*********************************省略代码
        if (!PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0))
    //*********************************省略代码
}

↓

LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
{
    //*********************************省略代码
            q->sendPostedEvents();
    //*********************************省略代码
}

↓

//QWindowsGuiEventDispatcher子类重写了父类QEventDispatcherWin32的sendPostedEvents,如果直接从processEvents代码跳转会直接执行到QEventDispatcherWin32::sendPostedEvents,因此看不到GUI事件处理
void QWindowsGuiEventDispatcher::sendPostedEvents() 
{
    //*********************************省略代码
    QWindowSystemInterface::sendWindowSystemEvents(m_flags);
}

↓

//通过QWindowSystemInterfacePrivate::getWindowSystemEvent()或QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent()从windowSystemEventQueue获取添加进windowSystemEventQueue的事件
bool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
{
    //*********************************省略代码
    while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) {
        QWindowSystemInterfacePrivate::WindowSystemEvent *event =
                flags & QEventLoop::ExcludeUserInputEvents ?
                        QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent() :
                        QWindowSystemInterfacePrivate::getWindowSystemEvent(); //从队列中获取出事件
    //*********************************省略代码
        if (QWindowSystemInterfacePrivate::eventHandler) {
            if (QWindowSystemInterfacePrivate::eventHandler->sendEvent(event))
                nevents++;
        } 
    //*********************************省略代码
    }
}

↓ 以Wheel类型为例
    
void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
{
    Q_TRACE_SCOPE(QGuiApplicationPrivate_processWindowSystemEvent, e->type);

    switch(e->type) {
	//*********************************省略代码
    case QWindowSystemInterfacePrivate::Wheel:
        QGuiApplicationPrivate::processWheelEvent(static_cast<QWindowSystemInterfacePrivate::WheelEvent *>(e));
        break;
    //*********************************省略代码
    }
}

↓
    
void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::WheelEvent *e)
{
    //*********************************省略代码
    if (e->nullWindow()) {//如果事件中没有reciver
        window = QGuiApplication::topLevelAt(globalPoint.toPoint()); 
        if (window) {
            QPointF delta = globalPoint - globalPoint.toPoint();
            localPoint = window->mapFromGlobal(globalPoint.toPoint()) + delta;
        }
    }

    //*********************************省略代码

#if QT_DEPRECATED_SINCE(5, 14)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED //QWhellEvent封装
     QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation,
                    mouse_buttons, e->modifiers, e->phase, e->source, e->inverted);
QT_WARNING_POP
#else
    QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta,
                   mouse_buttons, e->modifiers, e->phase, e->inverted, e->source);
#endif
     ev.setTimestamp(e->timestamp);
     QGuiApplication::sendSpontaneousEvent(window, &ev); //此处解释了reciver的来源和QWhellEvent封装
#else
     Q_UNUSED(e);
#endif // QT_CONFIG(wheelevent)
}

↓

bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)
{
    //*********************************省略代码
    return notifyInternal2(receiver, event);
}

↓

bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
{
    //*********************************省略代码
    return self->notify(receiver, event);
}

↓

bool QCoreApplication::notify(QObject *receiver, QEvent *event)
{
    //*********************************省略代码
    return doNotify(receiver, event);
}

↓

static bool doNotify(QObject *receiver, QEvent *event)
{
    //*********************************省略代码
    return receiver->isWidgetType() ? false : QCoreApplicationPrivate::notify_helper(receiver, event);
}

↓

bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{
    //*********************************省略代码
    consumed = receiver->event(event);
    return consumed;
}

参考调用栈:

MainWindow::mousePressEvent                      		mainwindow.cpp   
QWidget::event                                   		qwidget.cpp    
QMainWindow::event                               		qmainwindow.cpp   
QApplicationPrivate::notify_helper               		qapplication.cpp  
QApplication::notify                             		qapplication.cpp   
QCoreApplication::notifyInternal2                		qcoreapplication.cpp   
QCoreApplication::sendSpontaneousEvent           		qcoreapplication.cpp   
QApplicationPrivate::sendMouseEvent              		qapplication.cpp     
QWidgetWindow::handleMouseEvent                  		qwidgetwindow.cpp   
QWidgetWindow::event                             		qwidgetwindow.cpp  
QApplicationPrivate::notify_helper               		qapplication.cpp  
QApplication::notify                             		qapplication.cpp   
QCoreApplication::notifyInternal2                		qcoreapplication.cpp  
QCoreApplication::sendSpontaneousEvent           		qcoreapplication.cpp   
QGuiApplicationPrivate::processMouseEvent        		qguiapplication.cpp   
QGuiApplicationPrivate::processWindowSystemEvent 		qguiapplication.cpp  
QWindowSystemInterface::sendWindowSystemEvents   		qwindowsysteminterface.cpp 
QWindowsGuiEventDispatcher::sendPostedEvents     		qwindowsguieventdispatcher.cpp
QEventDispatcherWin32::processEvents             		qeventdispatcher_win.cpp     
QWindowsGuiEventDispatcher::processEvents        		qwindowsguieventdispatcher.cpp

参考文章:

Qt 之 消息机制(windows平台下)_qt windows消息处理-CSDN博客

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt事件循环是一个非常重要的机制,它负责接收和分发事件,保证 Qt 应用程序的正常运行。下面是简单的 Qt 事件循环源码分析: 1. Qt事件循环是通过 `QCoreApplication::exec()` 方法启动的。该方法首先会创建一个 `QEventLoop` 对象,然后进入一个无限循环。 2. 在事件循环中,`QEventLoop` 对象通过调用 `QCoreApplication::processEvents()` 方法来处理当前队列中的事件。该方法会检查是否有待处理的事件,如果没有,则线程会进入休眠状态,等待新的事件到来。 3. 当一个事件到来时,Qt 会根据事件的类型和目标对象,将事件分发给正确的接收者进行处理。接收者可以是窗口部件、控件、布局等。 4. 对于每个事件Qt调用接收者的对应方法来处理。例如,对于鼠标点击事件Qt调用接收者的 `mousePressEvent()` 方法来处理。 5. 在事件处理过程中,如果需要进行其他操作(如更新界面、执行定时器等),Qt 会将这些操作添加到事件队列中。 6. 当所有待处理的事件都被处理完毕后,Qt 会通过调用 `QCoreApplication::quit()` 方法退出事件循环,程序结束运行。 需要注意的是,Qt事件循环并不是单线程的。在多线程环境下,每个线程都可以有自己的事件循环,但每个线程只能有一个事件循环。当一个事件需要跨线程传递时,Qt 会通过事件队列和线程间的信号槽机制来实现。 以上是简单的 Qt 事件循环源码分析,如果您对具体的源码细节有更深入的需求,建议参考 Qt 的官方文档和源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值