• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天下

            記錄修行的印記

            [轉(zhuǎn)]淺議Qt的事件處理機(jī)制一

            淺議Qt的事件處理機(jī)制 一 .

                深入了解事件處理系統(tǒng)對(duì)于每個(gè)學(xué)習(xí)Qt人來(lái)說(shuō)非常重要,可以說(shuō),Qt是以事件驅(qū)動(dòng)的UI工具集。 大家熟知Signals
            /Slots在多線程的實(shí)現(xiàn)也依賴于Qt的事件處理機(jī)制。

                在Qt中,事件被封裝成一個(gè)個(gè)對(duì)象,所有的事件均繼承自抽象類QEvent.  接下來(lái)依次談?wù)凲t中有誰(shuí)來(lái)產(chǎn)生、分發(fā)、接受和處理事件:

                 
            1.  誰(shuí)來(lái)產(chǎn)生事件: 最容易想到的是我們的輸入設(shè)備,比如鍵盤、鼠標(biāo)產(chǎn)生的

            keyPressEvent,keyReleaseEvent,mousePressEvent,mouseReleaseEvent事件(他們被封裝成QMouseEvent和QKeyEvent),這些事件來(lái)自于底層的操作系統(tǒng),它們以異步的形式通知Qt事件處理系統(tǒng),后文會(huì)仔細(xì)道來(lái)。當(dāng)然Qt自己也會(huì)產(chǎn)生很多事件,比如QObject::startTimer()會(huì)觸發(fā)QTimerEvent. 用戶的程序可還以自己定制事件。

                 
            2.  誰(shuí)來(lái)接受和處理事件:答案是QObject。在Qt的內(nèi)省機(jī)制剖析一文已經(jīng)介紹QObject 類是整個(gè)Qt對(duì)象模型的心臟,事件處理機(jī)制是QObject三大職責(zé)(內(nèi)存管理、內(nèi)省(intropection)與事件處理制)之一。任何一個(gè)想要接受并處理事件的對(duì)象均須繼承自QObject,可以選擇重載QObject::event()函數(shù)或事件的處理權(quán)轉(zhuǎn)給父類。

                 
            3.   誰(shuí)來(lái)負(fù)責(zé)分發(fā)事件:對(duì)于non-GUI的Qt程序,是由QCoreApplication負(fù)責(zé)將QEvent分發(fā)給QObject的子類-Receiver. 對(duì)于Qt GUI程序,由QApplication來(lái)負(fù)責(zé)。

                  接下來(lái),將通過(guò)對(duì)代碼的解析來(lái)看看QT是利用event loop從事件隊(duì)列中獲取用戶輸入事件,又是如何將事件轉(zhuǎn)義成QEvents,并分發(fā)給相應(yīng)的QObject處理。

            #include 
            <QApplication>   
            #include 
            "widget.h"   
            //Section 1   
            int main(int argc, char *argv[])  
            {  
                QApplication app(argc, argv);  
                Widget window;  
            // Widget 繼承自QWidget   
                window.show();  
                
            return app.exec(); // 進(jìn)入Qpplication事件循環(huán),見section 2   
            }  
            // Section 2:    
            int QApplication::exec()  
            {  
               
            //skip codes   
               
            //簡(jiǎn)單的交給QCoreApplication來(lái)處理事件循環(huán)=〉section 3   
               return QCoreApplication::exec();  
            }  
            // Section 3   
            int QCoreApplication::exec()  
            {  
                
            //得到當(dāng)前Thread數(shù)據(jù)   
                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;  
                }  
                
            //檢查event loop是否已經(jīng)創(chuàng)建   
                if (!threadData->eventLoops.isEmpty()) {  
                    qWarning(
            "QCoreApplication::exec: The event loop is already running");  
                    
            return -1;  
                }  
                  
                QEventLoop eventLoop;  
                self
            ->d_func()->in_exec = true;  
                self
            ->d_func()->aboutToQuitEmitted = false;  
                
            //委任QEventLoop 處理事件隊(duì)列循環(huán) ==> Section 4   
                int returnCode = eventLoop.exec();  
                .  
                }  
                
            return returnCode;  
            }  
            // Section 4   
            int QEventLoop::exec(ProcessEventsFlags flags)  
            {  
               
            //這里的實(shí)現(xiàn)代碼不少,最為重要的是以下幾行   
               Q_D(QEventLoop); // 訪問(wèn)QEventloop私有類實(shí)例d   
                    try {  
                    
            //只要沒(méi)有遇見exit,循環(huán)派發(fā)事件   
                    while (!d->exit)  
                        processEvents(flags 
            | WaitForMoreEvents | EventLoopExec);  
                } 
            catch () {}  
            }  
            // Section 5   
            bool QEventLoop::processEvents(ProcessEventsFlags flags)  
            {  
                Q_D(QEventLoop);  
                
            if (!d->threadData->eventDispatcher)  
                    
            return false;  
                
            if (flags & DeferredDeletion)  
                    QCoreApplication::sendPostedEvents(
            0, QEvent::DeferredDelete);  
                
            //將事件派發(fā)給與平臺(tái)相關(guān)的QAbstractEventDispatcher子類 =>Section 6   
                return d->threadData->eventDispatcher->processEvents(flags);  
            }  
            #include 
            <QApplication>
            #include 
            "widget.h"
            //Section 1
            int main(int argc, char *argv[])
            {
                QApplication app(argc, argv);
                Widget window;  
            // Widget 繼承自QWidget
                window.show();
                
            return app.exec(); // 進(jìn)入Qpplication事件循環(huán),見section 2
            }
            // Section 2: 
            int QApplication::exec()
            {
               
            //skip codes
               
            //簡(jiǎn)單的交給QCoreApplication來(lái)處理事件循環(huán)=〉section 3
               return QCoreApplication::exec();
            }
            // Section 3
            int QCoreApplication::exec()
            {
                
            //得到當(dāng)前Thread數(shù)據(jù)
                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;
                }
                
            //檢查event loop是否已經(jīng)創(chuàng)建
                if (!threadData->eventLoops.isEmpty()) {
                    qWarning(
            "QCoreApplication::exec: The event loop is already running");
                    
            return -1;
                }
                
                QEventLoop eventLoop;
                self
            ->d_func()->in_exec = true;
                self
            ->d_func()->aboutToQuitEmitted = false;
                
            //委任QEventLoop 處理事件隊(duì)列循環(huán) ==> Section 4
                int returnCode = eventLoop.exec();
                .
                }
                
            return returnCode;
            }
            // Section 4
            int QEventLoop::exec(ProcessEventsFlags flags)
            {
               
            //這里的實(shí)現(xiàn)代碼不少,最為重要的是以下幾行
               Q_D(QEventLoop); // 訪問(wèn)QEventloop私有類實(shí)例d
                    try {
                    
            //只要沒(méi)有遇見exit,循環(huán)派發(fā)事件
                    while (!d->exit)
                        processEvents(flags 
            | WaitForMoreEvents | EventLoopExec);
                } 
            catch () {}
            }
            // Section 5
            bool QEventLoop::processEvents(ProcessEventsFlags flags)
            {
                Q_D(QEventLoop);
                
            if (!d->threadData->eventDispatcher)
                    
            return false;
                
            if (flags & DeferredDeletion)
                    QCoreApplication::sendPostedEvents(
            0, QEvent::DeferredDelete);
                
            //將事件派發(fā)給與平臺(tái)相關(guān)的QAbstractEventDispatcher子類 =>Section 6
                return d->threadData->eventDispatcher->processEvents(flags);
            }
             
            // Section 6,QTDIR/src/corelib/kernel/qeventdispatcher_win.cpp   
            // 這段代碼是完成與windows平臺(tái)相關(guān)的windows c++。 以跨平臺(tái)著稱的Qt同時(shí)也提供了對(duì)Symiban,Unix等平臺(tái)的消息派發(fā)支持   
            // 其事現(xiàn)分別封裝在QEventDispatcherSymbian和QEventDispatcherUNIX   
            // QEventDispatcherWin32派生自QAbstractEventDispatcher.   
            bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)  
            {  
                Q_D(QEventDispatcherWin32);  
                
            if (!d->internalHwnd)  
                    createInternalHwnd();  
                d
            ->interrupt = false;  
                emit awake();  
                
            bool canWait;  
                
            bool retVal = false;  
                
            bool seenWM_QT_SENDPOSTEDEVENTS = false;  
                
            bool needWM_QT_SENDPOSTEDEVENTS = false;  
                
            do {  
                    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;  
                            
            //從處理用戶輸入隊(duì)列中取出一條事件   
                            msg = d->queuedUserInputEvents.takeFirst();  
                        } 
            else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {  
                            
            // 從處理socket隊(duì)列中取出一條事件   
                            haveMessage = true;  
                            msg 
            = d->queuedSocketEvents.takeFirst();  
                        } 
            else {
                            
            //用非阻塞的PeekMessage()從消息隊(duì)列中取消息,然后刪除消息
                            haveMessage = PeekMessage(&msg, 000, 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  
                                    
            || msg.message == WM_MOUSEHWHEEL  
                                    
            || msg.message == WM_TOUCH  
                                    
            //
                                    || msg.message == WM_CLOSE)) {  
                                
            // 用戶輸入事件入隊(duì)列,待以后處理   
                                haveMessage = false;  
                                d
            ->queuedUserInputEvents.append(msg);  
                            }  
                            
            if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers)  
                                
            && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {  
                                
            // socket 事件入隊(duì)列,待以后處理   
                                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();
                            
                            
            //MsgWaitForMultipleObjectsEx 阻塞時(shí)仍可以響應(yīng)消息
                            
            //但它會(huì)在“對(duì)象被激發(fā)”或“消息到達(dá)隊(duì)列”時(shí)被喚醒而返回。MsgWaitForMultipleObjects()多接收一個(gè)參數(shù),允許指定哪些消息是觀察對(duì)象。
                            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) {
                            
            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 (!filterEvent(&msg)) {  
                                TranslateMessage(
            &msg);  
                                
            //將事件打包成message調(diào)用Windows API派發(fā)出去   
                                   
            //分發(fā)一個(gè)消息給窗口程序。消息被分發(fā)到回調(diào)函數(shù),將消息傳遞給windows系統(tǒng),windows處理完畢,會(huì)調(diào)用回調(diào)函數(shù) => section 7                       
                              DispatchMessage(&msg);  
                            }  
                        } 
            else if (waitRet >= WAIT_OBJECT_0 && waitRet < WAIT_OBJECT_0 + nCount) {
                            d
            ->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
                        } 
            else {
                            
            // nothing todo so break
                            break;
                        }
                        retVal 
            = true;
                    }
                        }               
                    }  
                } 
            while (canWait);  
                    
                
            return retVal;  


            // Section 7 windows窗口回調(diào)函數(shù) 定義在QTDIR/src/gui/kernel/qapplication_win.cpp   
            extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
            {  
                 
               
            //將消息重新封裝成QEvent的子類QMouseEvent ==> Section 8   
                result = widget->translateMouseEvent(msg);      
                 
            }  
               
            // Section 7 windows窗口回調(diào)函數(shù) 定義在QTDIR/src/gui/kernel/qapplication_win.cpp
            extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
            {
               
               
            //將消息重新封裝成QEvent的子類QMouseEvent ==> Section 8
                result = widget->translateMouseEvent(msg);    
               
            }
             

            從Section 
            1~Section7, Qt進(jìn)入QApplication的event loop,經(jīng)過(guò)層層委任,最終QEventloop的processEvent將通過(guò)與平臺(tái)相關(guān)的QAbstractEventDispatcher的子類QEventDispatcherWin32獲得用戶的用戶輸入事件,并將其打包成message后,通過(guò)標(biāo)準(zhǔn)Windows API ,把消息傳遞給了Windows OS,Windows OS得到通知后回調(diào)QtWndProc,  至此事件的分發(fā)與處理完成了一半的路程。

            在下文中,我們將進(jìn)一步討論當(dāng)我們收到來(lái)在Windows的回調(diào)后,事件又是怎么一步步打包成QEvent并通過(guò)QApplication分發(fā)給最終事件的接受和處理者QObject::
            event.

            下文的鏈接:
            http:
            //blog.csdn.net/changsheng230/archive/2010/12/22/6092978.aspx

            posted on 2013-07-04 11:59 天下 閱讀(2035) 評(píng)論(0)  編輯 收藏 引用 所屬分類: QT

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(4)

            隨筆分類(378)

            隨筆檔案(329)

            鏈接

            最新隨筆

            搜索

            最新評(píng)論

            久久精品午夜一区二区福利| 久久夜色tv网站| 久久99精品久久久久久水蜜桃| 久久99精品久久只有精品| 久久久亚洲欧洲日产国码是AV| 亚洲国产日韩欧美久久| 久久久久久久亚洲精品| 精品久久综合1区2区3区激情 | 99久久精品国产一区二区| 久久国产精品无码一区二区三区| 人妻久久久一区二区三区| 国产成人精品综合久久久| 一本久久a久久精品vr综合| 久久久久精品国产亚洲AV无码| 国产成人精品综合久久久久| 亚洲精品乱码久久久久久蜜桃不卡 | 久久一区二区三区免费| 亚洲国产成人久久精品99| 久久亚洲精品无码观看不卡| 色综合久久夜色精品国产| 久久这里只有精品首页| 熟妇人妻久久中文字幕| 99久久无色码中文字幕 | 97久久精品人人做人人爽| 国产福利电影一区二区三区久久久久成人精品综合 | 国产免费久久久久久无码| 久久久久久无码国产精品中文字幕 | 色婷婷噜噜久久国产精品12p| 欧美日韩精品久久久免费观看| 久久精品中文字幕一区| 久久99中文字幕久久| 久久这里有精品视频| 无码人妻久久一区二区三区免费丨| 国产综合久久久久| 久久伊人精品青青草原日本| 99久久99久久精品国产片果冻| 99久久精品费精品国产一区二区| 国产精品美女久久久久av爽| 久久福利资源国产精品999| 久久精品蜜芽亚洲国产AV| 久久九九久精品国产免费直播|