Qt 事件過濾器原理(installEventFilter函數)


Qt事件過濾器原理(installEventFilter函數)

事件過濾器用於攔截傳遞到目標對象的事件,這樣可以實現監視目標對象事件的作用。
1、Qt實現事件過濾器的步驟如下:
①、Qt調用
void QObject::installEventFilter (QObject* filterObj)
把filterObj對象安裝(或注冊)為事件過濾器,filterObj也稱為過濾器對象。事件過濾器通常在構造函數中進行注冊。
②、在上一步注冊的filterObj對象,通過調用
bool QObject::eventFilter(QObject* obj, QEvent* e);
來接收攔截到的事件。也就是說攔截到的事件在filterObj對象中的eventFilter函數中處理。eventFilter的第一個參數obj指向的是事件本應傳遞到的目標對象。
③、使用QObject::removeEventFilter(QObject *obj)函數可以刪除事件過濾器。
2、事件過濾器處理事件的規則
①、過濾器對象的eventFilter()函數可以接受或拒絕攔截到的事件,若該函數返回false,則表示事件需要作進一步處理,此時事件會被發送到目標對象本身進行處理(注意:這里並未向父對象進行傳遞),若evetnFilter()返回true,則表示停止處理該事件,此時目標對象和后面安裝的事件過濾器就無法獲得該事件。
②、若同一對象安裝了多個事件過濾器,則最后安裝的過濾器首先被激活。
3、為什么使用事件過濾器
使用事件過濾器可以簡化程序代碼。比如按鈕1和標簽1,對按下A鍵的事件響應相同的操作,若不使用事件過濾器,則需要分別子類化按鈕和標簽部件,並重新實現各自的事件處理函數。再如使用同一個子類化按鈕的類C創建的按鈕1和按鈕2,對按下鍵A,按鈕1和按鈕2需要作不同的響應,若不使用事件過濾器,則他們的響應是相同的,若使用事件過濾器,則可以攔截按鈕1或按鈕2的事件並作特殊處理。
4、理解事件過濾器
觀察者模式:其原理為,設有一目標對象S,它有多個觀察該對象的對象G1,G2,G3,當S發生變化時,S的觀察者會依情形改變自身。應用於Qt事件過濾器,則是,首先使用S的成員函數installEventFilter函數把G1,G2,G3設置為S的觀察者,所有本應傳遞給S的事件E,則先傳遞給觀察者G1,G2,G3,然后觀察者調用其成員函數eventFilter對傳遞進來的事件進行處理,若eventFilter返回true表示事件處理完畢,返回false則返回給被觀察者S進行處理。見圖2-13。
在這里插入圖片描述

示例2.22:事件過濾器的使用

 1 #include <QApplication>
 2 #include<QWidget>
 3 #include<QMouseEvent>
 4 #include<QPushButton>
 5 #include<QObject>
 6 #include <iostream>
 7 using namespace std;  8 class A:public QObject{public:  //該類的對象用作過濾器對象,使用事件過濾器需繼承QObject
 9 bool eventFilter(QObject *w, QEvent *e){ 10 if(e->type()==QEvent::MouseButtonPress) 11                 {cout<<w->objectName().toStdString(); //驗證w為事件本應到達的目標對象
12                 cout<<"=Ak"<<endl; 13                     return 1;  //返回1表示該事件不再進一步處理
14  } 15                 return 0;}  };  /*返回0表示其余事件交還給目標對象處理,本例應返回0,否則添加了該過濾器的安鈕會無法顯示。*/
16 class B:public A{public:   //繼承自類A
17 bool eventFilter(QObject *w, QEvent *e){ 18 if(e->type()==QEvent::MouseButtonPress){ 19 cout<<w->objectName().toStdString()<<"=Bk"<<endl; 20 return 0;} 21 return 0;} }; 22 class C:public QWidget{public: void mousePressEvent(QMouseEvent *e){cout<<"Ck"<<endl;}}; 23 class D:public QPushButton{public:void mousePressEvent(QMouseEvent *e){cout<<"DK"<<endl;}}; 24 
25 int main(int argc, char *argv[]){ 26 QApplication a(argc,argv); 27 //創建對象,注意:本例父對象應先創建,以避免生命期過早結束
28     A ma;       B mb;        C mc;        D *pd=new D;        D *pd1=new D; 29     pd->setText("AAA");    pd->move(22,22);      pd1->setText("BBB");    pd1->move(99,22); 30     //設置對象名
31     ma.setObjectName("ma");       mb.setObjectName("mb");       mc.setObjectName("mc"); 32     pd->setObjectName("pd");       pd1->setObjectName("pd1"); 33     //設置父對象
34     pd->setParent(&mc);    pd1->setParent(&mc); 35     mb.setParent(&ma);    //36      //注冊過濾器對象
37     pd->installEventFilter(&mb);  //
38     pd1->installEventFilter(&ma); //
39 
40 mc.resize(333,222); mc.show(); a.exec(); 41 return 0;     }

程序運行結果及說明(見圖2-14)
在這里插入圖片描述
當用鼠標按下按鈕AAA時,輸出pd=Bk和Dk。因為按鈕AAA安裝的過濾器對象為mb,因此由mb的eventFilter函數處理該事件,輸出pd=BK,此時mb::eventFilter()返回0,表示此事件需作進一步處理,於是把該事件傳遞給目標對象處理(即pd所指向的對象),注意:本例雖然為mb設置了父對象ma,但事件並不會傳遞給父對象處理,而是返回給目標對象。此時調用D::mousePressEvent函數,輸出Dk,至此事件處理結束。用鼠標按下按鈕BBB輸出pd1=Ak的原理略(較簡單)
示例2.23:添加多個事件過濾器

 1 #include <QApplication>
 2 #include<QWidget>
 3 #include<QMouseEvent>
 4 #include<QPushButton>
 5 #include<QObject>
 6 #include <iostream>
 7 using namespace std;  8 class A:public QObject{public:  //該類的對象用作過濾器對象,使用事件過濾器需繼承QObject
 9 bool eventFilter(QObject *w, QEvent *e){ 10 if(e->type()==QEvent::MouseButtonPress) 11                 {cout<<w->objectName().toStdString(); //驗證w為事件本應到達的目標對象
12                 cout<<"=Ak"<<endl; 13                     return 1;  //返回1表示該事件不再進一步處理
14  } 15                 return 0;}  };  /*返回0表示其余事件交還給目標對象處理,本例應返回0,否則添加了該過濾器的安鈕會無法顯示。*/
16 class B:public A{public:   //繼承自類A
17 bool eventFilter(QObject *w, QEvent *e){ 18 if(e->type()==QEvent::MouseButtonPress){ 19 cout<<w->objectName().toStdString()<<"=Bk"<<endl; 20 return 0;} 21 return 0;} }; 22 class C:public QWidget{public: void mousePressEvent(QMouseEvent *e){cout<<"Ck"<<endl;}}; 23 class D:public QPushButton{public:void mousePressEvent(QMouseEvent *e){cout<<"DK"<<endl;}}; 24 
25 int main(int argc, char *argv[]){ 26 QApplication a(argc,argv); 27 //創建對象,注意:本例父對象應先創建,以避免生命期過早結束
28     A ma;       B mb;        C mc;        D *pd=new D;        D *pd1=new D; 29     pd->setText("AAA");    pd->move(22,22);      pd1->setText("BBB");    pd1->move(99,22); 30     //設置對象名
31     ma.setObjectName("ma");       mb.setObjectName("mb");       mc.setObjectName("mc"); 32     pd->setObjectName("pd");       pd1->setObjectName("pd1"); 33     //設置父對象
34     pd->setParent(&mc);    pd1->setParent(&mc); 35     mb.setParent(&ma);    //36      //注冊過濾器對象
37     pd->installEventFilter(&mb);  //
38     pd1->installEventFilter(&ma); //
39 
40 mc.resize(333,222); mc.show(); a.exec(); 41 return 0;     }

程序運行結果及說明(見圖2-15)
在這里插入圖片描述
按鈕AAA安裝的過濾器對象依次為ma,mb,mc,mc1,
因此按下鼠標時,依次調用對象mc1,mc,mb,ma(即逆序)
的eventFilter函數,需要注意的是:當安裝了多個事件過濾
器之后,eventFilter函數返回0並不會使事件返回給目標對
象,而是傳遞給下一個過濾器對象,當所有過濾器對象都不處理該事件時才會傳遞給目標對象。


免責聲明!

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



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