青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天下

記錄修行的印記

[轉]淺議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 天下 閱讀(2057) 評論(0)  編輯 收藏 引用 所屬分類: QT

<2015年12月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

導航

統計

常用鏈接

留言簿(4)

隨筆分類(378)

隨筆檔案(329)

鏈接

最新隨筆

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美色视频在线| 亚洲精品视频免费| 一区二区三区精品国产| 麻豆精品精华液| 亚洲男人av电影| 国产精品美女一区二区| 亚洲欧美在线免费| 亚洲美女少妇无套啪啪呻吟| 美女诱惑黄网站一区| 亚洲视频国产视频| 亚洲二区在线视频| 欧美性一区二区| 欧美在线播放高清精品| 亚洲精品美女免费| 蜜臀av性久久久久蜜臀aⅴ四虎| 午夜精品亚洲| 欧美一区永久视频免费观看| 亚洲二区免费| 欧美国产日韩免费| 欧美日韩成人| 亚洲午夜激情| 亚洲国产你懂的| 国产欧美精品一区二区三区介绍| 久久九九免费视频| 亚洲人体一区| 亚洲午夜一区二区| 亚洲国产你懂的| 亚洲美女啪啪| 韩国在线一区| 一区二区高清在线| 在线免费精品视频| 亚洲午夜91| 麻豆国产精品va在线观看不卡| 女人香蕉久久**毛片精品| 久久久久一区二区三区四区| 亚洲新中文字幕| 免费毛片一区二区三区久久久| 国产区二精品视| 亚洲黄色精品| 好看的亚洲午夜视频在线| 99精品免费视频| ●精品国产综合乱码久久久久| 午夜精品视频一区| 欧美另类亚洲| 你懂的国产精品永久在线| 国产精品视频精品| 亚洲精品乱码久久久久久日本蜜臀 | 久久久久久久久久看片| 亚洲小说区图片区| 欧美伦理91i| 亚洲黑丝在线| 亚洲第一网站| 欧美在线影院在线视频| 欧美一级专区免费大片| 国产精品hd| 亚洲天堂男人| 亚洲尤物视频在线| 欧美日韩视频免费播放| 日韩特黄影片| 在线中文字幕不卡| 欧美日韩一本到| 妖精成人www高清在线观看| 一本色道久久加勒比精品| 欧美精品色网| 亚洲精品久久嫩草网站秘色| 一区二区三区精品国产| 欧美午夜国产| 亚洲与欧洲av电影| 久久久精品欧美丰满| 国产午夜一区二区三区| 欧美一区二区在线播放| 美女黄毛**国产精品啪啪| 揄拍成人国产精品视频| 久久偷窥视频| 亚洲三级视频| 亚洲午夜精品17c| 国产精品视频导航| 欧美专区第一页| 你懂的视频一区二区| 亚洲免费av电影| 欧美视频国产精品| 亚洲欧美另类中文字幕| 老巨人导航500精品| 亚洲国产精品久久91精品| 欧美美女喷水视频| 亚洲男人第一av网站| 久久久久久久999| 亚洲黑丝一区二区| 国产精品国产三级国产| 欧美一区二区视频97| 欧美激情久久久久久| 亚洲一区中文| 一区二区亚洲欧洲国产日韩| 欧美激情精品久久久久| 亚洲午夜羞羞片| 欧美福利专区| 亚洲制服少妇| 亚洲黄色在线视频| 99国产精品久久久久久久成人热| 一本一本久久a久久精品综合妖精| 亚洲美女网站| 欧美日韩在线三区| 午夜国产精品影院在线观看| 欧美福利视频| 久久aⅴ国产欧美74aaa| 亚洲国产精品悠悠久久琪琪 | 一本色道久久综合亚洲精品不| 欧美一区二区三区另类 | 亚洲精品资源| 国产亚洲一区二区在线观看| 免费一级欧美片在线观看| 亚洲午夜三级在线| 亚洲国产91| 久久免费视频网站| 亚洲影院在线| 日韩视频一区二区三区在线播放免费观看 | 久久国产综合精品| 日韩视频第一页| 老司机午夜精品| 午夜精品在线看| 亚洲无亚洲人成网站77777| 亚洲高清在线观看| 国产一区二区在线观看免费| 欧美高清视频在线观看| 久久精品夜夜夜夜久久| 亚洲免费在线观看视频| av成人福利| 亚洲高清视频一区| 牛人盗摄一区二区三区视频| 久久丁香综合五月国产三级网站| 国产美女精品| 国产精品免费看| 国产精品嫩草99a| 国产精品久久久久毛片软件| 欧美极品aⅴ影院| 欧美激情第9页| 欧美激情一区二区三区在线视频| 亚洲人成久久| 亚洲三级电影全部在线观看高清| 日韩一级黄色av| 91久久久久久| 亚洲欧洲精品天堂一级| 亚洲欧洲综合另类在线| 91久久精品久久国产性色也91| 欧美福利视频| 欧美va天堂| 欧美精品999| 欧美性生交xxxxx久久久| 国产精品porn| 国产日韩欧美日韩大片| 国产在线国偷精品产拍免费yy| 久久综合五月天婷婷伊人| 久久久99爱| 女主播福利一区| 欧美麻豆久久久久久中文| 欧美午夜不卡在线观看免费 | 国产偷自视频区视频一区二区| 久久免费视频网| 99精品视频一区二区三区| 欧美在线免费视屏| 理论片一区二区在线| 欧美波霸影院| 亚洲精品在线免费| 这里只有精品视频在线| 性感少妇一区| 久久另类ts人妖一区二区 | 亚洲综合国产激情另类一区| 亚洲欧美日韩综合国产aⅴ| 久久国产精品亚洲77777| 欧美高清视频一区| 一本综合久久| 久久九九久久九九| 欧美华人在线视频| 国产精品无码专区在线观看| 136国产福利精品导航网址| 一区二区三区鲁丝不卡| 久久国产福利| 亚洲国产成人在线播放| 一片黄亚洲嫩模| 久久国产精品一区二区| 欧美日韩亚洲一区二区| 国内揄拍国内精品久久| 一区二区日韩伦理片| 久久久久免费视频| 一区二区三区日韩精品| 久久天天躁狠狠躁夜夜av| 国产精品久久久久久久久借妻| 欧美日韩福利视频| 国内精品久久久久久久影视蜜臀| 欧美精品在线网站| 欧美福利一区二区三区| 国产日韩欧美日韩| 亚洲一区二区三区涩| 欧美激情一区三区| 久久av一区二区三区亚洲| 欧美视频在线播放| 亚洲欧洲一区二区天堂久久 | 国内偷自视频区视频综合| 亚洲视频免费看| 亚洲国产精品悠悠久久琪琪|