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

天下

記錄修行的印記

[轉]淺議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

<2012年6月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

導航

統計

常用鏈接

留言簿(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>
            亚洲欧美日韩国产成人| 国产精品免费看| 国产欧美日韩麻豆91| 久久福利资源站| 欧美亚洲一级| 欧美在线免费一级片| 欧美在线播放高清精品| 欧美一区二区久久久| 日韩视频一区二区| 欧美日韩不卡视频| 午夜久久影院| 亚洲精品视频在线观看网站| 久久精品论坛| 亚洲免费中文| 亚洲美女中出| 亚洲福利视频网| 国产精品视频免费观看| 性欧美xxxx大乳国产app| 亚洲日本成人在线观看| 亚洲国产精品一区| 亚洲一本视频| 久久国产直播| 亚洲成色999久久网站| 欧美va亚洲va国产综合| 欧美不卡激情三级在线观看| 日韩视频在线一区二区| 欧美亚洲免费电影| 免费看黄裸体一级大秀欧美| 国产精品二区影院| 一区二区三区在线视频播放| 亚洲美女黄色| 久久国产成人| 亚洲精品国产精品国自产观看浪潮| av不卡在线观看| 久久久国产成人精品| 欧美精品在线观看91| 国产亚洲欧美另类一区二区三区| 红桃视频一区| 亚洲自拍偷拍一区| 亚洲电影免费观看高清完整版在线观看 | 亚洲福利精品| 亚洲综合清纯丝袜自拍| 免费人成网站在线观看欧美高清 | 国产欧美欧洲在线观看| 亚洲国产专区| 久久国产精品电影| 日韩一本二本av| 美国十次了思思久久精品导航| 欧美三日本三级少妇三2023| 亚洲国产毛片完整版| 欧美在线免费播放| 在线精品国产欧美| 日韩视频在线观看免费| 欧美一区91| 亚洲日韩欧美视频一区| 久久久五月天| 亚洲高清在线| 欧美激情一区二区三区在线视频| 国产精品久久久久aaaa樱花| 久久久久久久一区二区三区| 国产精品视频内| 亚洲一区二区免费视频| 亚洲国产精品欧美一二99| 久久精品国产2020观看福利| 国产精品欧美久久久久无广告| 亚洲精品国产欧美| 欧美电影免费观看网站| 久久久久久久网| 精品电影一区| 久久夜色精品一区| 久久综合色8888| 亚洲国产成人午夜在线一区| 久久精品三级| 欧美一区三区三区高中清蜜桃 | 欧美丰满高潮xxxx喷水动漫| 久久久噜噜噜| 亚洲级视频在线观看免费1级| 欧美福利一区| 欧美电影在线观看| 日韩视频在线观看| 99re视频这里只有精品| 国产精品国产三级国产专播精品人| 一本色道**综合亚洲精品蜜桃冫| 亚洲国产国产亚洲一二三| 欧美精品久久久久久久久久| 亚洲深夜福利网站| 午夜视频精品| 在线观看欧美视频| 亚洲欧洲在线观看| 国产精品免费一区二区三区在线观看 | 欧美成人精品一区二区| 免费观看欧美在线视频的网站| 亚洲激情视频在线播放| av成人免费在线观看| 中文在线资源观看网站视频免费不卡 | 韩国一区电影| 久热精品视频| 欧美日韩美女在线| 午夜欧美视频| 美日韩丰满少妇在线观看| 国产精品99久久久久久久女警| 亚洲一区二区黄| 亚洲成人在线视频播放| 9人人澡人人爽人人精品| 欧美国产精品日韩| 91久久久久久久久| 一区二区三区四区五区精品视频 | 亚洲蜜桃精久久久久久久| 宅男精品视频| 亚洲电影欧美电影有声小说| 一本色道综合亚洲| 在线观看日产精品| 亚洲亚洲精品在线观看| 亚洲国产精品久久人人爱蜜臀| 在线综合亚洲欧美在线视频| 亚洲黄色免费电影| 欧美亚洲在线| 亚洲一级片在线观看| 久久婷婷久久一区二区三区| 亚洲欧洲av一区二区| 欧美激情国产日韩| 久久综合999| 国产精品一区二区在线观看网站| 亚洲国产精品999| 国内综合精品午夜久久资源| 中文网丁香综合网| 亚洲天堂av综合网| 欧美剧在线免费观看网站| 美国十次成人| 韩日精品在线| 亚洲欧美国产另类| 亚洲免费网址| 欧美视频国产精品| 亚洲精品系列| 欧美视频亚洲视频| 亚洲精品女av网站| 伊人久久婷婷色综合98网| 欧美国产日韩a欧美在线观看| 免费看精品久久片| 你懂的一区二区| 亚洲国产91精品在线观看| 久久精品国产亚洲精品| 久久国产一区| 一区在线观看| 欧美高清视频www夜色资源网| 欧美精品啪啪| 亚洲福利国产| 欧美国产第一页| 日韩视频中文字幕| 亚洲影院一区| 亚洲看片免费| ●精品国产综合乱码久久久久| 国产日韩欧美夫妻视频在线观看| 国产精品系列在线播放| 欧美日韩国产一区二区三区| 欧美日韩在线视频一区二区| 国产精品日本一区二区| 亚洲第一在线综合网站| 亚洲——在线| 亚洲欧洲精品天堂一级| 久久久久se| 欧美国产日韩一区二区| 一区二区三区在线视频免费观看| 久久精品国产亚洲一区二区三区 | 久久深夜福利免费观看| 亚洲第一毛片| 欧美日韩大陆在线| 亚洲午夜视频在线| 久久婷婷人人澡人人喊人人爽| 亚洲电影免费在线| 欧美三级乱码| 欧美一区永久视频免费观看| 美女诱惑一区| 亚洲一区bb| 好吊成人免视频| 欧美精品一区二区三区蜜桃| 亚洲一区二区高清| 欧美大片免费观看在线观看网站推荐| 日韩写真在线| 国产色产综合产在线视频| 久久夜色精品国产噜噜av| 亚洲三级观看| 久久久亚洲高清| 亚洲精品中文在线| 国产女主播在线一区二区| 久久综合久色欧美综合狠狠 | 亚洲三级色网| 久久久蜜臀国产一区二区| 日韩西西人体444www| 红桃视频一区| 国产精品欧美久久| 欧美韩日亚洲| 久久精品免费看| 久久婷婷亚洲| 亚洲影视在线播放| 亚洲激情国产精品| 国内精品久久久久国产盗摄免费观看完整版 | 亚洲一二区在线| 亚洲福利在线观看| 国产亚洲精品福利|