详解 QT 源码之 Qt 事件机制原理

移动开发
本文介绍的是 QT 源码之 Qt 事件机制原理,解决在用Qt写Gui程序的时候,出现的问题,先来看本文.

QT 源码之 Qt 事件机制原理是本文要介绍的内容,在用Qt写Gui程序的时候,在main函数里面最后依据都是app.exec();很多书上对这句的解释是,使 Qt 程序进入消息循环。下面我们就到exec()函数内部,来看一下他的实现原理。
Let's go!
首先来到QTDIR\src\corelib\kernel\qcoreapplication.cpp

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;  
    }  
    //判断eventLoop是否已经创建  
    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;  
    //创建eventLoop  
    int returnCode = eventLoop.exec();  
    threadData->quitNow = false;  
    if (self) {  
        self->d_func()->in_exec = false;  
        //退出程序  
        emit self->aboutToQuit();  
        sendPostedEvents(0, QEvent::DeferredDelete);  
    }  
    return returnCode;  
}  
再来到qeventloop.cpp中。  
int QEventLoop::exec(ProcessEventsFlags flags)  
{  
    Q_D(QEventLoop);  
    if (d->threadData->quitNow)  
        return -1;  
    //已经调用过exec了。  
    if (d->inExec) {  
        qWarning("QEventLoop::exec: instance %p has already called exec()", this);  
        return -1;  
    }  
    d->inExec = true;  
    d->exit = false;  
    ++d->threadData->loopLevel;  
    //将事件类对象压入线程结构体中  
    d->threadData->eventLoops.push(this);  
    // remove posted quit events when entering a new event loop  
    // 这句不用翻译了把!  
    if (qApp->thread() == thread())  
        QCoreApplication::removePostedEvents(qApp, QEvent::Quit);  
#if defined(QT_NO_EXCEPTIONS)  
    while (!d->exit)  
        //这里才是关键,我们还要继续跟踪进去。  
        processEvents(flags | WaitForMoreEvents);  
#else  
    try {  
        while (!d->exit)  
            processEvents(flags | WaitForMoreEvents);  
    } catch (...) {  
        //如果使用了EXCEPTION,则继续对下一条时间进行处理。  
        qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"  
                 "exceptions from an event handler is not supported in Qt. You must\n"  
                 "reimplement QApplication::notify() and catch all exceptions there.\n");  
        throw;  
    }  
#endif  
    //退出eventloop前,将时间对象从线程结构中取出。  
    QEventLoop *eventLoop = d->threadData->eventLoops.pop();  
    Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");  
    Q_UNUSED(eventLoop); // --release warning  
 
    d->inExec = false;  
    --d->threadData->loopLevel;  
    //退出事件循环。  
    return d->returnCode;  
}  
 
来到了processEvents函数:  
bool QEventLoop::processEvents(ProcessEventsFlags flags)  
{  
    Q_D(QEventLoop);  
    //判断事件分派器是否为空。  
    if (!d->threadData->eventDispatcher)  
        return false;  
    if (flags & DeferredDeletion)  
        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);  
    //调用不同平台下的事件分派器来处理事件。  
    return d->threadData->eventDispatcher->processEvents(flags);  
}  
processEvents是在QAbstractEventDispatcher类中定义的纯虚方法。在QEventDispatcherWin32类有processEvents的实现。  
bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)  
{  
    Q_D(QEventDispatcherWin32);  
    //内部数据创建。registerClass注册窗口类,createwindow创建窗体。  
    //注册socket notifiers,启动所有的normal timers  
    if (!d->internalHwnd)  
        createInternalHwnd();  
    d->interrupt = false;  
    emit awake();  
 
    bool canWait;  
    bool retVal = false;  
    do {  
        QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);  
        DWORD waitRet = 0;  
        HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1];  
        QVarLengthArray<MSG> processedTimers;  
        while (!d->interrupt) {  
            DWORD nCount = d->winEventNotifierList.count();  
            Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);  
            MSG msg;  
            bool haveMessage;  
            if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {  
                // process queued user input events处理用户输入事件,放入队列中。  
                haveMessage = true;  
                msg = d->queuedUserInputEvents.takeFirst();  
            } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {  
                // process queued socket events  处理socket事件,放入队列中。  
                haveMessage = true;  
                msg = d->queuedSocketEvents.takeFirst();  
            } else {  
                //从消息队列中取消息,同PeekMessage  
                haveMessage = winPeekMessage(&msg, 0, 0, 0, PM_REMOVE);  
                if (haveMessage && (flags & QEventLoop::ExcludeUserInputEvents)  
                    && ((msg.message >= WM_KEYFIRST  
                         && msg.message <= WM_KEYLAST)  
                        || (msg.message >= WM_MOUSEFIRST  
                            && msg.message <= WM_MOUSELAST)  
                        || msg.message == WM_MOUSEWHEEL)) {  
                    // queue user input events for later processing  
                    haveMessage = false;  
                    d->queuedUserInputEvents.append(msg);  
                }  
                if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers)  
                    && (msg.message == WM_USER && msg.hwnd == d->internalHwnd)) {  
                    // queue socket events for later processing  
                    haveMessage = false;  
                    d->queuedSocketEvents.append(msg);  
                }  
            }  
            if (!haveMessage) {  
                // no message - check for signalled objects  
                for (int i=0; i<(int)nCount; i++)  
                    pHandles[i] = d->winEventNotifierList.at(i)->handle();  
                //注册signal--slot。  
                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) {   
                //处理timer事件  
                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 (!filterEvent(&msg)) {  
                    TranslateMessage(&msg);  
                    QT_WA({  
                        DispatchMessage(&msg);  
                    } , {  
                        DispatchMessageA(&msg);  
                    });  
                }  
            } else if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) {  
                //处理signal--slot  
                d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));  
            } else {  
                // nothing todo so break  
                break;  
            }  
            retVal = true;  
        }  
        // still nothing - wait for message or signalled objects  
        QThreadData *ddata = d->threadData;  
        canWait = (!retVal  
                   && data->canWait  
                   && !d->interrupt  
                   && (flags & QEventLoop::WaitForMoreEvents));  
        if (canWait) {  
            DWORD nCount = d->winEventNotifierList.count();  
            Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);  
            for (int i=0; i<(int)nCount; i++)  
                pHandles[i] = d->winEventNotifierList.at(i)->handle();  
            emit aboutToBlock();  
            waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);  
            emit awake();  
            if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) {  
                d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));  
                retVal = true;  
            }  
        }  
    } while (canWait);  
    return retVal;  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.
  • 190.
  • 191.
  • 192.
  • 193.
  • 194.
  • 195.
  • 196.
  • 197.
  • 198.
  • 199.
  • 200.
  • 201.
  • 202.
  • 203.
  • 204.
  • 205.
  • 206.
  • 207.
  • 208.
  • 209.

小结:关于详解 QT 源码之 Qt 事件机制原理的内容介绍完了,基本属于代码实现的内容,最后希望本文对你有帮助!

责任编辑:zhaolei 来源: 互联网
相关推荐

2011-06-23 14:40:13

Qt 信号

2011-06-23 13:38:27

QT 元对象 信号

2011-06-23 11:16:39

Qt Excel

2011-07-01 14:20:59

Qt 事件

2011-07-01 14:14:34

Qt 事件

2011-06-23 15:32:05

Qt Windows消息

2011-06-23 13:25:42

QT 源码 窗口

2011-06-28 16:18:24

Qt QObject

2011-06-23 15:10:39

Qt 窗体

2011-07-05 18:32:52

QT 信号 机制

2011-07-05 18:40:19

QT 信号 机制

2011-06-29 16:14:59

Qt 事件 过滤器

2011-06-29 17:20:20

Qt 内存 QOBJECT

2021-09-01 06:48:16

AndroidGlide缓存

2011-06-23 14:27:48

QT QLibrary 动态库

2021-08-17 13:41:11

AndroidView事件

2011-08-29 14:59:26

QtEvent事件

2011-07-04 14:50:49

QT Event 事件

2011-06-24 17:38:09

Qt 坐标 事件

2011-07-01 15:04:49

Qt 内省
点赞
收藏

51CTO技术栈公众号