Qt的事件分發過程

看了篇文章,說先要子類化QEvent,然後定義自己的QEvent::Type,然後重寫QWidget::event()函數,然後就可以調用QCoreApplication::sendEvent()或者QCoreApplication:;postEvent()發送事件就好了。但我比較笨,還是雲山霧罩,不知道怎麼下手。

怎麼子類化QEvent?在哪裏定義自己的QEvent::Type?在哪裏重寫QWidget::event()函數?在哪裏調用QCoreApplication::sendEvent()或者QCoreApplication:;postEvent()發送事件?

在百度裏搜索開了篇文章對我有啓發http://bluemask.net/p/1215/ ,在google中搜索how to subclass QEvent也搜到一篇對我有啓發的http://www.java2s.com/Code/Cpp/Qt/SubclassQEvent.htm 。(google的英文搜索真不錯!)

後來我就想,那Qt的發明人是怎麼定義事件的呢?其實站在Qt發明人的角度,QEvent就是他們的“自定義事件”!Ok!這就好辦了!看看Qt發明人怎麼定義的QEvent,看看他們怎麼用自己定義的QEvent,不就回答了文章開頭的倆問題了嘛!O(∩_∩)O~

我把整個過程總結爲“長官定義事件”----->“信使傳遞事件”---->“軍隊接收並響應事件”。

我通過Qt Assistant查找那些與事件相關的類,總結如下:

1、Qt中定義事件的長官:QEvent

QEvent的任務就是定義一些事件類型Type,它們都定義在了一個enum裏。這就是教程中告訴我們的要子類化QEvent,派生出MyEvent,然後在MyEvent中定義事件類型QEvent::Type。

我們子類化的時候模仿一個QEvent就好了,而且是繼承,好些都不用子類做了,看一下QEvent類中的成員變量和成員函數,就這些東西:


好了,我們通過子類化QEvent,把派生出來的MyEvent看做長官,它定義了具體某個事件。下面看誰是信使。


2、Qt中傳遞事件的信使:QCoreApplication(QApplication繼承自QCoreApplication)

我們看看QCoreApplication中定義的一些函數,這些函數就是我們經常遇到的那些與傳遞事件和過濾事件有關的函數,見下圖:

Public Functions:

Static Public Members:



所以,到這裏我們就可以明確了,你要用QCoreApplication的static public類型的函數入sendEvent或postEvent函數來傳遞送信,要注意:當使用sendEvent時,你的事件要在棧上建立,sendEvent會直接調用notify把事件傳遞給士兵,不走事件隊列;而用postEvent時,你的事件要在堆上建立,即要用new來創建,postEvent會把你的事件追加進事件隊列(詳細過程請看http://blog.csdn.net/michealtx/article/details/6865891。你還可以通過重載notify來影響送信過程。

3、Qt中接收響應事件的軍隊:QWidget(這是Qt中的widget之母,諸如QMainWindow、QPushBUtton等等都是繼承自QWidget)

我們看看QWidget中與事件有關的成員:


看到了嗎?這些就是event handler,即事件處理函數,這是幹活的那幫人。裏面有我們熟悉的mousePressEvent()、keyPressEvent()等常用的事件處理函數,它們都是protected virtual 類型的,可以重載。所以呀,我們可以子類化QWidget,從而繼承得到好些個event handler,當然也可以自己定義event handler!相當於自己創造士兵來響應事件。通過山寨QWidget,就可以創造自己的軍隊!

還有一點就是,當事件到達軍隊的時候,要先審查再分發,審查就是要經過事件過濾,分發就是通過對經過審查的事件進行判斷再把它分給那個相應的士兵這就又涉及到一個類QObject,這是Qt的萬類之母,這個類中有兩個函數一個是eventFilter(),另一個是event()。要先子類化QObject來創建一個監控者,這個監控者重載eventFilter(),來爲軍隊過濾事件。然後還要在軍隊(QWidget)通過調用installEventFilter ( QObject * filterObj )來安裝過濾器,參數中的filterOb即爲監控者。最後在軍隊(QWidget)中重載event()來分發事件,把事件分給對應會幹這個活的士兵(event handler)。


好了,我理解的大體過程就是這樣,我是Qt新手,可能有錯的地方,希望路過的大牛能給與指正,我將不勝感激!


什麼話也不如來個例程給力!:

我建立的是Qt Console Application,工程叫MyEvent,下面是main.cpp中的代碼:

  1. #include <QtGui/QApplication>  
  2. #include <QCoreApplication>  
  3. #include <QEvent>  
  4. #include <QObject>  
  5. #include <QDebug>  
  6.   
  7. static const QEvent::Type MyEventType = (QEvent::Type)QEvent::registerEventType(QEvent::User+100);  
  8.   
  9. //長官  
  10. class MyEvent: public QEvent  
  11. {  
  12. public:  
  13.     MyEvent(Type MyEventType):QEvent(MyEventType){}  
  14. };  
  15.   
  16. //信使  
  17. class MySender: public QCoreApplication  
  18. {  
  19. public:  
  20.     MySender(int argc,char *argv[]):QCoreApplication(argc,argv){}  
  21.   
  22. public:  
  23.     bool notify(QObject *receiver, QEvent *event);  
  24.   
  25. };  
  26.   
  27. bool MySender::notify(QObject *receiver, QEvent *event)  
  28. {  
  29.     if(event->type() == MyEventType)  
  30.     {  
  31.         qDebug()<<"MyEventType is coming!";  
  32.         //return true;  
  33.         /*這裏不能return true,因爲重寫notify就是在事件被向下傳遞之前截住它, 
  34.         隨便搞它,搞完了還得給QCoreApplication::notify向下傳遞,除非在mySender.notify 
  35.         實現了事件向下傳遞的那一套。直接返回的話myArmy就收不到這個事件,因爲執行完這個 
  36.         mySender.notify的return true後,事件傳遞被人爲的在半截終止了 
  37.         (見Qt事件處理的五個層次http://blog.csdn.net/michealtx/article/details/6865891 ) 
  38.         ,下面的myArmy的安裝的過濾器和它自己的event都不會收到這個事件,更甭提最後幹活 
  39.         的myEventHandler了。所以在主函數中執行完mySender.sendEvent把myEvent 
  40.         交給mySender.notify這個敗家子兒後,就執行mySender.exec進入其它事件的循環了。這就是 
  41.         問題http://topic.csdn.net/u/20111012/19/78036d16-c163-40f9-a05c-3b7d6f4e9043.html 
  42.         出現的原因。感謝1+1=2大牛!非常感謝! 
  43.         */  
  44.     }  
  45.     return QCoreApplication::notify(receiver,event);  
  46. }  
  47.   
  48. //軍隊  
  49. class MyArmy: public QObject  
  50. {  
  51. public:  
  52.     void MyEventHandler(QEvent *event);  
  53.     bool event(QEvent *event);  
  54. };  
  55.   
  56. void MyArmy::MyEventHandler(QEvent *event)  
  57. {  
  58.     qDebug()<<"The event is being handled!";  
  59.     event->accept();  
  60. }  
  61.   
  62. bool MyArmy::event(QEvent *event)  
  63. {  
  64.     if(event->type() == MyEventType)  
  65.     {  
  66.         qDebug()<<"event() is dispathing MyEvent";  
  67.         MyEventHandler(event);//調用事件處理函數  
  68.         if((MyEvent*)event->isAccepted())  
  69.         {  
  70.             qDebug()<<"The event has been handled!";  
  71.             return true;  
  72.         }  
  73.     }  
  74.     return QObject::event(event);  
  75. }  
  76.   
  77. //監控者  
  78. class MyWatcher: public QObject  
  79. {  
  80. public:  
  81.     bool eventFilter(QObject *watched, QEvent *event);  
  82. };  
  83.   
  84. bool MyWatcher::eventFilter(QObject *watched, QEvent *event)  
  85. {  
  86.     if(event->type() == MyEventType)  
  87.     {  
  88.         qDebug()<<"I don't wanna filter MyEventType";  
  89.         return false;  
  90.     }  
  91.     return QObject::eventFilter(watched,event);  
  92. }  
  93.   
  94.   
  95. int main(int argc, char *argv[])  
  96. {  
  97.     //QCoreApplication a(argc, argv);  
  98.     MySender mySender(argc,argv);  
  99.   
  100.     MyArmy myArmy;  
  101.     MyWatcher myWatcher;  
  102.     myArmy.installEventFilter(&myWatcher);//安裝事件過濾器  
  103.   
  104.     MyEvent myEvent(MyEventType);  
  105.     mySender.sendEvent(&myArmy,&myEvent);  
  106.     return mySender.exec();  

運行結果:


轉載於:http://blog.csdn.net/michealtx/article/details/6866094

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章