Qt 自定義事件的實現


初學Qt,用了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來影響送信過程。

注意C++:在函數內下列聲明

一種是在棧上創建類對象,形式如下:CSomeClass someObject;

一種是在堆上創建(動態分配),形式如下:CSomeClass *pSomeObject = new CSomeClass();

具體一定要看這一篇文章:https://www.devbean.net/2014/02/cpp-create-object-on-heap-or-stack/    《C++:在堆上創建對象,還是在棧上?》

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

運行結果:

 

 

好了,就這樣了!可能有錯誤或不准確的地方!望路過的大牛指點!

轉自:http://blog.csdn.net/MichealTX/article/details/6866094


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM