Qt事件的详细介绍和原理

作者 : admin 本文共18382个字,预计阅读时间需要46分钟 发布时间: 2024-06-16 共1人阅读

介绍

事件类型:
1、窗口系统事件spontaneous。
2、异步事件PostEvent。
3、同步事件SendEvent

窗体系统事件spontaneous
代表事件有:各类外设事件,如鼠标单双击、滚轮、移动,键盘按键等事件。
使用场景:该类事件都是窗体系统进行捕获的,我们一般不需要进行操作,除非我们需要模拟鼠标、键盘的事件。

异步事件PostEvent
代表事件有:绘图时的update事件。
使用场景:不需要马上回应的异步情况下,模拟各种事件。
例子:
//模拟按键点击

    QTextEdit* text = new QTextEdit(this);
    QPushButton* btn = new QPushButton("模拟",this);
    text->setGeometry(100,0,400,300);
    connect(btn,&QPushButton::clicked,this,[=]()
    {
        QKeyEvent *key = new QKeyEvent(QEvent::KeyPress, ' ', Qt::NoModifier, "A");
        QApplication::postEvent(text, key); //_currentLineEdit

//        QKeyEvent *key = new QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier);
//        QApplication::postEvent(text, key); //_currentLineEdit
    });

同步事件PostEvent
代表事件有:绘图时的repaint事件。
使用场景:需要发送后立刻执行的情况下,模拟各种事件。
例子:
//模拟按键点击

    QTextEdit* text = new QTextEdit(this);
    QPushButton* btn = new QPushButton("模拟",this);
    text->setGeometry(100,0,400,300);
    connect(btn,&QPushButton::clicked,this,[=]()
    {
        QKeyEvent *key = new QKeyEvent(QEvent::KeyPress, ' ', Qt::NoModifier, "A");
        QApplication::sendEvent(text, key); //_currentLineEdit

//        QKeyEvent *key = new QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier);
//        QApplication::sendEvent(text, key); //_currentLineEdit
    });

sendEvent、PostEvent、自定义事件:详细实例。

原理

sendEvent的原理需要查看它的源代码就能发现它同步执行的方式了。
1、

bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event)
{
    Q_TRACE(QCoreApplication_sendEvent, receiver, event, event->type());
    // 如果事件不为空,则将 spont 标志设置为 false
    if (event)
        event->spont = false;
    // 调用内部函数 notifyInternal2 发送事件,并返回结果
    return notifyInternal2(receiver, event);
}

直接调用notifyInternal2接口.
2、

bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
{
    bool selfRequired = QCoreApplicationPrivate::threadRequiresCoreApplication();
    if (!self && selfRequired)
        return false;

    bool result = false;
    void *cbdata[] = { receiver, event, &result };
    if (QInternal::activateCallbacks(QInternal::EventNotifyCallback, cbdata)) {
        return result;
    }

    QObjectPrivate *d = receiver->d_func();
    QThreadData *threadData = d->threadData;
    QScopedScopeLevelCounter scopeLevelCounter(threadData);
    if (!selfRequired)
        return doNotify(receiver, event);
    return self->notify(receiver, event);
}

如果selfRequired的请求不存在则调用doNotify,如果存在则调用到notify。
3、

bool QCoreApplication::notify(QObject *receiver, QEvent *event)
{
    // ~QCoreApplication()析构调用后不会传递任何事件
    if (QCoreApplicationPrivate::is_app_closing)
        return true;
    return doNotify(receiver, event);
}

判断程序打开时才调用doNotify。
4、

static bool doNotify(QObject *receiver, QEvent *event)
{
    if (receiver == 0) {                        // serious error
        qWarning("QCoreApplication::notify: Unexpected null receiver");
        return true;
    }
    
#ifndef QT_NO_DEBUG
QCoreApplicationPrivate::checkReceiverThread(receiver);
#endif

return receiver->isWidgetType() ? false : QCoreApplicationPrivate::notify_helper(receiver, event);
}

调用notify_helper。
5、

bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{
Q_TRACE(QCoreApplication_notify_entry, receiver, event, event->type());
// send to all application event filters (only does anything in the main thread)
if (QCoreApplication::self
&& receiver->d_func()->threadData->thread == mainThread()
&& QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) {
Q_TRACE(QCoreApplication_notify_event_filtered, receiver, event, event->type());
return true;
}
// send to all receiver event filters
if (sendThroughObjectEventFilters(receiver, event)) {
Q_TRACE(QCoreApplication_notify_event_filtered, receiver, event, event->type());
return true;
}
Q_TRACE(QCoreApplication_notify_before_delivery, receiver, event, event->type());
// deliver the event
const bool consumed = receiver->event(event);
Q_TRACE(QCoreApplication_notify_after_delivery, receiver, event, event->type(), consumed);
return consumed;
}
bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiver, QEvent *event)
{
// We can't access the application event filters outside of the main thread (race conditions)
Q_ASSERT(receiver->d_func()->threadData->thread == mainThread());
if (extraData) {
// application event filters are only called for objects in the GUI thread
for (int i = 0; i < extraData->eventFilters.size(); ++i) {
QObject *obj = extraData->eventFilters.at(i);
if (!obj)
continue;
if (obj->d_func()->threadData != threadData) {
qWarning("QCoreApplication: Application event filter cannot be in a different thread.");
continue;
}
if (obj->eventFilter(receiver, event))
return true;
}
}
return false;
}
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;
}

在这里可以看到事件是如何处理的:
先送入Application的事件过滤器,看看是否在事件过滤器中处理,再查看receiver是否有此事件的过滤器,最后将事件送入receiver的event接口。从整个过程来看,可以认为sendEvent直接调用了receiver的event接口。因此,可以认为处理方式为同步处理方式。

说到spontaneous事件和postevent事件的原理,就需要了解main函数中“a.exec()”,因为他们的执行都是在exec这个函数中执行的。
1、
spontaneous窗体系统事件一般都是通过系统层面的中断来捕获事件的。
postEvent源码:

void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
{
Q_TRACE(QCoreApplication_postEvent_entry, receiver, event, event->type());
if (receiver == 0) {
qWarning("QCoreApplication::postEvent: Unexpected null receiver");
delete event;
return;
}
QThreadData * volatile * pdata = &receiver->d_func()->threadData;
QThreadData *data = *pdata;
if (!data) {
// posting during destruction? just delete the event to prevent a leak
delete event;
return;
}
// lock the post event mutex
data->postEventList.mutex.lock();
// 判断事件是否在另外一个线程
while (data != *pdata) {
data->postEventList.mutex.unlock();
data = *pdata;
if (!data) {
// 发送期间如果事件已经不存在了,则销毁它,防止内存泄漏。
delete event;
return;
}
data->postEventList.mutex.lock();
}
QMutexUnlocker locker(&data->postEventList.mutex);
// 如果这是可一个压缩事件,请执行压缩,例如短时间多次触发update就会触发压缩事件。
if (receiver->d_func()->postedEvents
&& self && self->compressEvent(event, receiver, &data->postEventList)) {
Q_TRACE(QCoreApplication_postEvent_event_compressed, receiver, event);
return;
}
if (event->type() == QEvent::DeferredDelete)
receiver->d_ptr->deleteLaterCalled = true;
if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) {
// remember the current running eventloop for DeferredDelete
// events posted in the receiver's thread.
// Events sent by non-Qt event handlers (such as glib) may not
// have the scopeLevel set correctly. The scope level makes sure that
// code like this:
//     foo->deleteLater();
//     qApp->processEvents(); // without passing QEvent::DeferredDelete
// will not cause "foo" to be deleted before returning to the event loop.
// If the scope level is 0 while loopLevel != 0, we are called from a
// non-conformant code path, and our best guess is that the scope level
// should be 1. (Loop level 0 is special: it means that no event loops
// are running.)
int loopLevel = data->loopLevel;
int scopeLevel = data->scopeLevel;
if (scopeLevel == 0 && loopLevel != 0)
scopeLevel = 1;
static_cast<QDeferredDeleteEvent *>(event)->level = loopLevel + scopeLevel;
}
// 删除异常上的事件以防止内存泄漏,直到该事件在postEventList中正确拥有为止
QScopedPointer<QEvent> eventDeleter(event);
Q_TRACE(QCoreApplication_postEvent_event_posted, receiver, event, event->type());
//将事件添加到postEventList中,注意这里的优先级第一个最高,最后一个优先级最低
data->postEventList.addEvent(QPostEvent(receiver, event, priority));
eventDeleter.take();
event->posted = true;
++receiver->d_func()->postedEvents;
data->canWait = false;
locker.unlock();
QAbstractEventDispatcher* dispatcher = data->eventDispatcher.loadAcquire();
if (dispatcher)
dispatcher->wakeUp();
}

从上面可以看出,postEvent实际上是将事件添加到receiver所在线程中的一个队列中,至于这个队列所在的线程什么时候处理这个事件,postEvent是无法控制的。
2、

int QApplication::exec()
{
return QGuiApplication::exec();
}
int QCoreApplication::exec()
{
if (!QCoreApplicationPrivate::checkInstance("exec"))
return -1;
QThreadData *threadData = self->d_func()->threadData;
if (threadData != QThreadData::current()) {
qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
return -1;
}
if (!threadData->eventLoops.isEmpty()) {
qWarning("QCoreApplication::exec: The event loop is already running");
return -1;
}
threadData->quitNow = false;
QEventLoop eventLoop;
self->d_func()->in_exec = true;
self->d_func()->aboutToQuitEmitted = false;
int returnCode = eventLoop.exec();
threadData->quitNow = false;
if (self)
self->d_func()->execCleanup();
return returnCode;
}
int QEventLoop::exec(ProcessEventsFlags flags)
{
Q_D(QEventLoop);
//we need to protect from race condition with QThread::exit
QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex);
if (d->threadData->quitNow)
return -1;
if (d->inExec) {
qWarning("QEventLoop::exec: instance %p has already called exec()", this);
return -1;
}
struct LoopReference {
QEventLoopPrivate *d;
QMutexLocker &locker;
bool exceptionCaught;
LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)
{
d->inExec = true;
d->exit.storeRelease(false);
++d->threadData->loopLevel;
d->threadData->eventLoops.push(d->q_func());
locker.unlock();
}
~LoopReference()
{
if (exceptionCaught) {
qWarning("Qt has caught an exception thrown from an event handler. Throwing
"
"exceptions from an event handler is not supported in Qt.
"
"You must not let any exception whatsoever propagate through Qt code.
"
"If that is not possible, in Qt 5 you must at least reimplement
"
"QCoreApplication::notify() and catch all exceptions there.
");
}
locker.relock();
QEventLoop *eventLoop = d->threadData->eventLoops.pop();
Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
Q_UNUSED(eventLoop); // --release warning
d->inExec = false;
--d->threadData->loopLevel;
}
};
LoopReference ref(d, locker);
// remove posted quit events when entering a new event loop
QCoreApplication *app = QCoreApplication::instance();
if (app && app->thread() == thread())
QCoreApplication::removePostedEvents(app, QEvent::Quit);
#ifdef Q_OS_WASM
// Partial support for nested event loops: Make the runtime throw a JavaSrcript
// exception, which returns control to the browser while preserving the C++ stack.
// Event processing then continues as normal. The sleep call below never returns.
// QTBUG-70185
if (d->threadData->loopLevel > 1)
emscripten_sleep(1);
#endif
while (!d->exit.loadAcquire())
processEvents(flags | WaitForMoreEvents | EventLoopExec);
ref.exceptionCaught = false;
return d->returnCo
}
bool QEventLoop::processEvents(ProcessEventsFlags flags)
{
Q_D(QEventLoop);
if (!d->threadData->hasEventDispatcher())
return false;
return d->threadData->eventDispatcher.load()->processEvents(flags);
}    

调用到了这个位置时,就需要区分系统了,processEvents这个函数是来源于QAbstractEventDispatcher的一个纯虚函数,在Windows中是调用继承QAbstractEventDispatcher的QEventDispatcherWin32的processEvents;在linux系统中是继承QAbstractEventDispatcher的QEventDIspatcherUNIX的processEvents。

bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
{
Q_D(QEventDispatcherWin32);
if (!d->internalHwnd) {
createInternalHwnd();
wakeUp(); // trigger a call to sendPostedEvents()
}
d->interrupt.store(false);
emit awake();
bool canWait;
bool retVal = false;
bool seenWM_QT_SENDPOSTEDEVENTS = false;
bool needWM_QT_SENDPOSTEDEVENTS = false;
do {
DWORD waitRet = 0;
DWORD nCount = 0;
HANDLE *pHandles = nullptr;
if (d->winEventNotifierActivatedEvent) {
nCount = 1;
pHandles = &d->winEventNotifierActivatedEvent;
}
QVarLengthArray<MSG> processedTimers;
while (!d->interrupt.load()) {
MSG msg;
bool haveMessage;
if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
// 处理排队的用户输入事件。
haveMessage = true;
msg = d->queuedUserInputEvents.takeFirst();
} else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
// 处理排队的套接字事件
haveMessage = true;
msg = d->queuedSocketEvents.takeFirst();
} else {
haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
if (haveMessage) {
if (flags.testFlag(QEventLoop::ExcludeUserInputEvents)
&& isUserInputMessage(msg.message)) {
// 将用户输入事件排队以供稍后处理
d->queuedUserInputEvents.append(msg);
continue;
}
if ((flags & QEventLoop::ExcludeSocketNotifiers)
&& (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
// 将套接字事件排队以供稍后处理
d->queuedSocketEvents.append(msg);
continue;
}
}
}
if (!haveMessage) {
// no message - check for signalled objects
waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE);
if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) {
// a new message has arrived, process it
continue;
}
}
if (haveMessage) {
// WinCE doesn't support hooks at all, so we have to call this by hand :(
if (!d->getMessageHook)
(void) qt_GetMessageHook(0, PM_REMOVE, reinterpret_cast<LPARAM>(&msg));
if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
if (seenWM_QT_SENDPOSTEDEVENTS) {
// when calling processEvents() "manually", we only want to send posted
// events once
needWM_QT_SENDPOSTEDEVENTS = true;
continue;
}
seenWM_QT_SENDPOSTEDEVENTS = true;
} else if (msg.message == WM_TIMER) {
// avoid live-lock by keeping track of the timers we've already sent
bool found = false;
for (int i = 0; !found && i < processedTimers.count(); ++i) {
const MSG processed = processedTimers.constData()[i];
found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam);
}
if (found)
continue;
processedTimers.append(msg);
} else if (msg.message == WM_QUIT) {
if (QCoreApplication::instance())
QCoreApplication::instance()->quit();
return false;
}
if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) {
// 将事件打包成message调用Windows API派发出去
TranslateMessage(&msg);
// 分发一个消息给窗口程序。消息被分发到回调函数,将消息传递给windows系统,windows处理完毕,会调用回调函数。
DispatchMessage(&msg);
}
} else if (waitRet - WAIT_OBJECT_0 < nCount) {
activateEventNotifiers();
} else {
// nothing todo so break
break;
}
retVal = true;
}
// still nothing - wait for message or signalled objects
canWait = (!retVal
&& !d->interrupt.load()
&& (flags & QEventLoop::WaitForMoreEvents));
if (canWait) {
emit aboutToBlock();
waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
emit awake();
if (waitRet - WAIT_OBJECT_0 < nCount) {
activateEventNotifiers();
retVal = true;
}
}
} while (canWait);
if (!seenWM_QT_SENDPOSTEDEVENTS && (flags & QEventLoop::EventLoopExec) == 0) {
// when called "manually", always send posted events
sendPostedEvents();
}
if (needWM_QT_SENDPOSTEDEVENTS)
PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0);
return retVal;
}

TranslateMessage(&msg)和DispatchMessage(&msg)这两个函数将事件打包成msg分发给windows的窗口回调函数。

 QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// ...
// 检查message是否属于Qt可转义的鼠标事件
if (qt_is_translatable_mouse_event(message))
{
if (QApplication::activePopupWidget() != 0)
{ // in popup mode
POINT curPos = msg.pt;
// 取得鼠标点击坐标所在的QWidget指针,它指向我们在main创建的widget实例
QWidget* w = QApplication::widgetAt(curPos.x, curPos.y);
if (w)
{
widget = (QETWidget*)w;
}
}
if (!qt_tabletChokeMouse)
{
// 对,就在这里。Windows的回调函数将鼠标事件分发回给了Qt Widget
// => Section 2-2
result = widget->translateMouseEvent(msg);  // mouse event
}
}
// ...
}

以上就是windows窗口回调函数了。通过translateMouseEvent来将事件分发出去。

bool QETWidget::translateMouseEvent(const MSG &msg)
{
// ...这里有很长的一段代码可以忽略
// 让我们看一下sendMouseEvent的声明
// widget是事件的接受者;e是封装好的QMouseEvent
// ==> Section 2-3
res = QApplicationPrivate::sendMouseEvent(target,
&e, alienWidget, this, &qt_button_down,
qt_last_mouse_receiver);
}
bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
QWidget *alienWidget, QWidget *nativeWidget,
QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,
bool spontaneous, bool onlyDispatchEnterLeave)
{
Q_ASSERT(receiver);
Q_ASSERT(event);
Q_ASSERT(nativeWidget);
Q_ASSERT(buttonDown);
if (alienWidget && !isAlien(alienWidget))
alienWidget = 0;
QPointer<QWidget> receiverGuard = receiver;
QPointer<QWidget> nativeGuard = nativeWidget;
QPointer<QWidget> alienGuard = alienWidget;
QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget();
const bool graphicsWidget = nativeWidget->testAttribute(Qt::WA_DontShowOnScreen);
bool widgetUnderMouse = QRectF(receiver->rect()).contains(event->localPos());
// Clear the obsolete leaveAfterRelease value, if mouse button has been released but
// leaveAfterRelease has not been updated.
// This happens e.g. when modal dialog or popup is shown as a response to button click.
if (leaveAfterRelease && !*buttonDown && !event->buttons())
leaveAfterRelease = 0;
if (*buttonDown) {
if (!graphicsWidget) {
// Register the widget that shall receive a leave event
// after the last button is released.
if ((alienWidget || !receiver->internalWinId()) && !leaveAfterRelease && !QWidget::mouseGrabber())
leaveAfterRelease = *buttonDown;
if (event->type() == QEvent::MouseButtonRelease && !event->buttons())
*buttonDown = 0;
}
} else if (lastMouseReceiver && widgetUnderMouse) {
// Dispatch enter/leave if we move:
// 1) from an alien widget to another alien widget or
//    from a native widget to an alien widget (first OR case)
// 2) from an alien widget to a native widget (second OR case)
if ((alienWidget && alienWidget != lastMouseReceiver)
|| (isAlien(lastMouseReceiver) && !alienWidget)) {
if (activePopupWidget) {
if (!QWidget::mouseGrabber())
dispatchEnterLeave(alienWidget ? alienWidget : nativeWidget, lastMouseReceiver, event->screenPos());
} else {
dispatchEnterLeave(receiver, lastMouseReceiver, event->screenPos());
}
}
}
#ifdef ALIEN_DEBUG
qDebug() << "QApplicationPrivate::sendMouseEvent: receiver:" << receiver
<< "pos:" << event->pos() << "alien" << alienWidget << "button down"
<< *buttonDown << "last" << lastMouseReceiver << "leave after release"
<< leaveAfterRelease;
#endif
// We need this quard in case someone opens a modal dialog / popup. If that's the case
// leaveAfterRelease is set to null, but we shall not update lastMouseReceiver.
const bool wasLeaveAfterRelease = leaveAfterRelease != 0;
bool result = true;
// This code is used for sending the synthetic enter/leave events for cases where it is needed
// due to other events causing the widget under the mouse to change. However in those cases
// we do not want to send the mouse event associated with this call, so this enables us to
// not send the unneeded mouse event
if (!onlyDispatchEnterLeave) {
if (spontaneous)
result = QApplication::sendSpontaneousEvent(receiver, event);
else
result = QApplication::sendEvent(receiver, event);
}
if (!graphicsWidget && leaveAfterRelease && event->type() == QEvent::MouseButtonRelease
&& !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) {
// Dispatch enter/leave if:
// 1) the mouse grabber is an alien widget
// 2) the button is released on an alien widget
QWidget *enter = 0;
if (nativeGuard)
enter = alienGuard ? alienWidget : nativeWidget;
else // The receiver is typically deleted on mouse release with drag'n'drop.
enter = QApplication::widgetAt(event->globalPos());
dispatchEnterLeave(enter, leaveAfterRelease, event->screenPos());
leaveAfterRelease = 0;
lastMouseReceiver = enter;
} else if (!wasLeaveAfterRelease) {
if (activePopupWidget) {
if (!QWidget::mouseGrabber())
lastMouseReceiver = alienGuard ? alienWidget : (nativeGuard ? nativeWidget : 0);
} else {
lastMouseReceiver = receiverGuard ? receiver : QApplication::widgetAt(event->globalPos());
}
}
return result;
}
bool QCoreApplication::sendSpontaneousEvent(QObject *receiver, QEvent *event)
{
Q_TRACE(QCoreApplication_sendSpontaneousEvent, receiver, event, event->type());
if (event)
event->spont = true;
return notifyInternal2(receiver, event);
}

从上面两个函数就可以知道translateMouseEvent–>sendMouseEvent–>sendSpontaneousEvent或者sendEvent。到了sendEvent我们知道后面的调用流程了。其中sendSpontaneousEvent函数里面其实也是和sendEvent一样来进行后面的调用的。
postEvent和spontaneous调用流程较复杂,总结一下:
1、postEvent和spontaneous事件加入到postEventList的链表中。
2、在main函数的exec里面存在一个eventloop系统循环函数。
3、系统循环函数区分windous和linux系统后从processEvents中依次取出各种事件,其中就包括postEvent和spontaneous事件,将它们打包成MSG事件分发给窗口回调函数。
4、窗口回调函数收到MSG事件后调用translateMouseEvent–>sendMouseEvent–>sendSpontaneousEvent–>sendEvent。

本站无任何商业行为
个人在线分享 » Qt事件的详细介绍和原理
E-->