• <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>

            天下

            記錄修行的印記

            [轉]淺議Qt的事件處理機制一

            淺議Qt的事件處理機制 一 .

                深入了解事件處理系統對于每個學習Qt人來說非常重要,可以說,Qt是以事件驅動的UI工具集。 大家熟知Signals
            /Slots在多線程的實現也依賴于Qt的事件處理機制。

                在Qt中,事件被封裝成一個個對象,所有的事件均繼承自抽象類QEvent.  接下來依次談談Qt中有誰來產生、分發、接受和處理事件:

                 
            1.  誰來產生事件: 最容易想到的是我們的輸入設備,比如鍵盤、鼠標產生的

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

                 
            2.  誰來接受和處理事件:答案是QObject。在Qt的內省機制剖析一文已經介紹QObject 類是整個Qt對象模型的心臟,事件處理機制是QObject三大職責(內存管理、內省(intropection)與事件處理制)之一。任何一個想要接受并處理事件的對象均須繼承自QObject,可以選擇重載QObject::event()函數或事件的處理權轉給父類。

                 
            3.   誰來負責分發事件:對于non-GUI的Qt程序,是由QCoreApplication負責將QEvent分發給QObject的子類-Receiver. 對于Qt GUI程序,由QApplication來負責。

                  接下來,將通過對代碼的解析來看看QT是利用event loop從事件隊列中獲取用戶輸入事件,又是如何將事件轉義成QEvents,并分發給相應的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(); // 進入Qpplication事件循環,見section 2   
            }  
            // Section 2:    
            int QApplication::exec()  
            {  
               
            //skip codes   
               
            //簡單的交給QCoreApplication來處理事件循環=〉section 3   
               return QCoreApplication::exec();  
            }  
            // Section 3   
            int QCoreApplication::exec()  
            {  
                
            //得到當前Thread數據   
                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是否已經創建   
                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 處理事件隊列循環 ==> Section 4   
                int returnCode = eventLoop.exec();  
                .  
                }  
                
            return returnCode;  
            }  
            // Section 4   
            int QEventLoop::exec(ProcessEventsFlags flags)  
            {  
               
            //這里的實現代碼不少,最為重要的是以下幾行   
               Q_D(QEventLoop); // 訪問QEventloop私有類實例d   
                    try {  
                    
            //只要沒有遇見exit,循環派發事件   
                    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);  
                
            //將事件派發給與平臺相關的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(); // 進入Qpplication事件循環,見section 2
            }
            // Section 2: 
            int QApplication::exec()
            {
               
            //skip codes
               
            //簡單的交給QCoreApplication來處理事件循環=〉section 3
               return QCoreApplication::exec();
            }
            // Section 3
            int QCoreApplication::exec()
            {
                
            //得到當前Thread數據
                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是否已經創建
                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 處理事件隊列循環 ==> Section 4
                int returnCode = eventLoop.exec();
                .
                }
                
            return returnCode;
            }
            // Section 4
            int QEventLoop::exec(ProcessEventsFlags flags)
            {
               
            //這里的實現代碼不少,最為重要的是以下幾行
               Q_D(QEventLoop); // 訪問QEventloop私有類實例d
                    try {
                    
            //只要沒有遇見exit,循環派發事件
                    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);
                
            //將事件派發給與平臺相關的QAbstractEventDispatcher子類 =>Section 6
                return d->threadData->eventDispatcher->processEvents(flags);
            }
             
            // Section 6,QTDIR/src/corelib/kernel/qeventdispatcher_win.cpp   
            // 這段代碼是完成與windows平臺相關的windows c++。 以跨平臺著稱的Qt同時也提供了對Symiban,Unix等平臺的消息派發支持   
            // 其事現分別封裝在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;  
                            
            //從處理用戶輸入隊列中取出一條事件   
                            msg = d->queuedUserInputEvents.takeFirst();  
                        } 
            else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {  
                            
            // 從處理socket隊列中取出一條事件   
                            haveMessage = true;  
                            msg 
            = d->queuedSocketEvents.takeFirst();  
                        } 
            else {
                            
            //用非阻塞的PeekMessage()從消息隊列中取消息,然后刪除消息
                            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)) {  
                                
            // 用戶輸入事件入隊列,待以后處理   
                                haveMessage = false;  
                                d
            ->queuedUserInputEvents.append(msg);  
                            }  
                            
            if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers)  
                                
            && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {  
                                
            // socket 事件入隊列,待以后處理   
                                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 阻塞時仍可以響應消息
                            
            //但它會在“對象被激發”或“消息到達隊列”時被喚醒而返回。MsgWaitForMultipleObjects()多接收一個參數,允許指定哪些消息是觀察對象。
                            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調用Windows API派發出去   
                                   
            //分發一個消息給窗口程序。消息被分發到回調函數,將消息傳遞給windows系統,windows處理完畢,會調用回調函數 => 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窗口回調函數 定義在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窗口回調函數 定義在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進入QApplication的event loop,經過層層委任,最終QEventloop的processEvent將通過與平臺相關的QAbstractEventDispatcher的子類QEventDispatcherWin32獲得用戶的用戶輸入事件,并將其打包成message后,通過標準Windows API ,把消息傳遞給了Windows OS,Windows OS得到通知后回調QtWndProc,  至此事件的分發與處理完成了一半的路程。

            在下文中,我們將進一步討論當我們收到來在Windows的回調后,事件又是怎么一步步打包成QEvent并通過QApplication分發給最終事件的接受和處理者QObject::
            event.

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

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

            <2012年8月>
            2930311234
            567891011
            12131415161718
            19202122232425
            2627282930311
            2345678

            導航

            統計

            常用鏈接

            留言簿(4)

            隨筆分類(378)

            隨筆檔案(329)

            鏈接

            最新隨筆

            搜索

            最新評論

            大蕉久久伊人中文字幕| 亚洲精品无码久久千人斩| 亚洲一区二区三区日本久久九| 久久亚洲精品人成综合网| 97精品国产97久久久久久免费| 久久综合一区二区无码| 无码人妻久久久一区二区三区| 狠狠色丁香久久综合五月| 久久久久99这里有精品10| 韩国免费A级毛片久久| 久久AAAA片一区二区| 久久一日本道色综合久久| 国产精品无码久久久久| 性欧美丰满熟妇XXXX性久久久| 久久高潮一级毛片免费| 久久久久久国产精品免费无码| 久久久久免费视频| 青青草国产精品久久| 精品久久久久久亚洲精品| 欧美日韩精品久久免费| 青青热久久国产久精品| 国产福利电影一区二区三区久久老子无码午夜伦不 | 久久精品人人做人人爽电影| 亚洲Av无码国产情品久久| 国内精品久久久久影院网站| 欧美激情精品久久久久| 99精品久久精品一区二区| 久久亚洲精品成人av无码网站| 久久亚洲AV无码精品色午夜麻豆| 久久久噜噜噜久久| 看全色黄大色大片免费久久久| 国产精品成人久久久久三级午夜电影| 久久棈精品久久久久久噜噜| 亚洲综合日韩久久成人AV| 97久久国产露脸精品国产| 久久精品国产久精国产果冻传媒 | 久久久久人妻精品一区 | 狠狠人妻久久久久久综合| 久久久久久a亚洲欧洲aⅴ| 91久久精品视频| 亚洲精品乱码久久久久久蜜桃 |