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

天下

記錄修行的印記

[轉]淺議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>
            久久蜜桃资源一区二区老牛| 久久综合九色99| 久久精视频免费在线久久完整在线看| 亚洲午夜精品一区二区| 亚洲素人一区二区| 亚洲欧美电影在线观看| 午夜在线精品偷拍| 久久久久久久网站| 欧美激情自拍| 一本色道久久88亚洲综合88| 这里只有精品在线播放| 久久国内精品视频| 欧美片在线观看| 国产欧美日韩| 久久国产毛片| 一区二区三区欧美在线观看| 亚洲国产精品欧美一二99| 亚洲精品日韩激情在线电影| 99在线热播精品免费| 亚洲综合视频一区| 久久久www成人免费毛片麻豆 | 欧美午夜片欧美片在线观看| 国产欧美在线观看一区| 在线观看欧美| 亚洲一区二区三区在线| 久久中文欧美| 国产精品99久久久久久有的能看| 久久精品国产一区二区三区免费看| 欧美阿v一级看视频| 国产日韩欧美在线观看| aa国产精品| 奶水喷射视频一区| 午夜精品免费在线| 欧美日韩精品一区二区天天拍小说 | 亚洲人成网站在线观看播放| 亚洲视频一二三| 欧美gay视频| 国产视频在线观看一区二区三区| 99re6这里只有精品视频在线观看| 久久精品99无色码中文字幕| 一本大道久久a久久综合婷婷| 久久av一区| 国产欧美日韩91| 亚洲在线视频网站| 99视频精品在线| 欧美人与禽性xxxxx杂性| 亚洲狠狠婷婷| 亚洲第一页中文字幕| 久久国产精品久久久久久| 国产欧美日韩亚洲精品| 亚洲自拍16p| 亚洲精品日韩欧美| 欧美日本韩国一区二区三区| 亚洲精品视频在线播放| 欧美电影免费观看| 久久影院午夜论| 亚洲国产va精品久久久不卡综合| 久久久久久久网站| 久久精品国产2020观看福利| 国产亚洲综合精品| 久久久xxx| 久久九九热re6这里有精品| 国产在线播放一区二区三区| 久久精品国产免费观看| 欧美在线资源| 在线不卡免费欧美| 亚洲国产精品成人精品| 久久免费高清| 久久天天狠狠| 久久精品欧美| 亚洲第一黄色| 亚洲高清资源综合久久精品| 欧美精品一区二区三区四区| 亚洲一区二区精品在线| 亚洲专区在线视频| 国产一区二区三区最好精华液| 久久精品国产第一区二区三区| 久久xxxx| 日韩天天综合| 亚洲男人的天堂在线观看| 国内在线观看一区二区三区| 欧美大片在线观看| 欧美三区在线| 久久精品综合| 欧美激情亚洲国产| 午夜精品久久久久久久99黑人| 欧美一区二区观看视频| 亚洲国产你懂的| 亚洲图色在线| 亚洲成人中文| 99国产麻豆精品| 国内精品视频久久| 亚洲三级免费电影| 国产一区二区三区四区hd| 欧美激情bt| 国产九九精品| 亚洲日本va午夜在线影院| 国产日韩在线不卡| 亚洲日韩欧美视频| 国产一区二区欧美日韩| 夜夜夜精品看看| 在线不卡亚洲| 亚洲欧美日韩一区二区在线| 亚洲精品美女| 欧美综合激情网| 亚洲网站视频| 美女91精品| 久久久久国产精品一区二区| 欧美精品久久久久久久免费观看 | 欧美专区在线| 欧美片第1页综合| 另类av一区二区| 国产精品xxxxx| 亚洲国产精品黑人久久久| 国产午夜精品一区二区三区欧美| 亚洲欧洲久久| 亚洲成人在线| 久久精品国产精品| 欧美一级专区免费大片| 欧美日韩在线电影| 亚洲激情小视频| 亚洲国产精品久久91精品| 久久aⅴ国产欧美74aaa| 欧美一区二区三区成人| 国产精品成人一区二区艾草| 欧美国产91| 亚洲国产mv| 在线成人小视频| 欧美一区二区在线看| 亚洲综合首页| 欧美亚州一区二区三区| 亚洲精选国产| 亚洲视频www| 国产精品二区三区四区| 国产精品99久久久久久www| 亚洲视频网在线直播| 欧美日韩成人一区| 亚洲九九爱视频| 亚洲午夜激情免费视频| 国产精品都在这里| 亚洲欧美日韩一区在线观看| 久久av红桃一区二区小说| 国产美女高潮久久白浆| 午夜精品免费| 久久成人人人人精品欧| 国产亚洲欧美日韩在线一区| 久久精品国产第一区二区三区最新章节 | 欧美精品久久一区二区| 亚洲国产精品电影| 亚洲精品一区久久久久久| 欧美精品日韩精品| 一本一本久久| 久久精品国产一区二区三| 国语自产精品视频在线看一大j8| 久久久久一区二区| 亚洲国产导航| 亚洲免费在线视频一区 二区| 国产精品久久久久久五月尺| 欧美一区二区| 亚洲高清av| 亚洲欧美成人精品| 狠狠色丁香婷婷综合| 欧美成年人网| 亚洲午夜高清视频| 麻豆久久婷婷| av成人国产| 国产视频在线观看一区二区| 蜜臀av一级做a爰片久久| 99re6这里只有精品| 久久久福利视频| 亚洲精品一区二区三区樱花| 国产精品国色综合久久| 久久人人爽爽爽人久久久| 日韩午夜在线观看视频| 久久精品国产视频| 亚洲精品网址在线观看| 国产欧美日韩另类一区| 欧美精品九九| 久久亚洲不卡| 亚洲欧美在线另类| 亚洲人成网站999久久久综合| 久久久999| 亚洲网站视频福利| 亚洲国产成人91精品| 国产一区二区成人| 欧美三级网址| 欧美成人精品三级在线观看| 亚洲欧美日韩视频二区| 亚洲精品日韩一| 欧美高清在线播放| 久久天堂av综合合色| 欧美一区二区免费观在线| 一区二区电影免费在线观看| 精品999网站| 国产日韩一级二级三级| 国产精品区一区| 亚洲精选大片| 一区二区三区亚洲| 国产欧美日韩中文字幕在线| 欧美日韩精品免费观看视一区二区|