自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

QT類 Qevent事件處理過程 事件過濾器

移動(dòng)開發(fā)
本文介紹的是QT類 Qevent事件處理過程 事件過濾器,事件的操作應(yīng)該友們很感興趣,先來看你本文介紹。

QT類 Qevent事件處理過程 事件過濾器 是本文要介紹的內(nèi)容,我們直接進(jìn)入內(nèi)容。

事件處理流程:

某個(gè)事件發(fā)生------>exec()循環(huán)會(huì)接收到這個(gè)事件------>

創(chuàng)建一個(gè)事件對(duì)象,并將對(duì)象傳遞給QObject::event()------>

在QWidget::event()函數(shù)中,分配給特定的事件處理函數(shù)------>

在QButton的事件處理函數(shù)中emit(clicked消息)

前面說到了事件的作用,下面來看看我們?nèi)绾蝸斫邮帐录;貞浺幌虑懊娴拇a,我們?cè)谧宇愔兄貙懥耸录瘮?shù),以便讓這些子類按照我們的需要完成某些功能,就像下面的代碼:

  1. void MyLabel::mousePressEvent(QMouseEvent * event)  
  2. {  
  3.         if(event->button() == Qt::LeftButton) {  
  4.                 // do something  
  5.         } else {  
  6.                 QLabel::mousePressEvent(event);  
  7.         }  

上面的代碼和前面類似,在鼠標(biāo)按下的事件中檢測,如果按下的是左鍵,做我們的處理工作,如果不是左鍵,則調(diào)用父類的函數(shù)。這在某種程度上說,是把事件向上傳遞給父類去響應(yīng),也就是說,我們?cè)谧宇愔?ldquo;忽略”了這個(gè)事件。

我們可以把Qt的事件傳遞看成鏈狀:如果子類沒有處理這個(gè)事件,就會(huì)繼續(xù)向其他類傳遞。其實(shí),Qt的事件對(duì)象都有一個(gè)accept()函數(shù)和ignore()函數(shù)。正如它們的名字,前者用來告訴Qt,事件處理函數(shù)“接收”了這個(gè)事件,不要再傳遞;后者則告訴Qt,事件處理函數(shù)“忽略”了這個(gè)事件,需要繼續(xù)傳遞,尋找另外的接受者。在事件處理函數(shù)中,可以使用isAccepted()來查詢這個(gè)事件是不是已經(jīng)被接收了。

事實(shí)上,我們很少使用accept()和ignore()函數(shù),而是想上面的示例一樣,如果希望忽略事件,只要調(diào)用父類的響應(yīng)函數(shù)即可。記得我們?cè)?jīng)說過,Qt中的事件大部分是protected的,因此,重寫的函數(shù)必定存在著其父類中的響應(yīng)函數(shù),這個(gè)方法是可行的。為什么要這么做呢?因?yàn)槲覀儫o法確認(rèn)父類中的這個(gè)處理函數(shù)沒有操作,如果我們?cè)谧宇愔兄苯雍雎允录?,Qt不會(huì)再去尋找其他的接受者,那么父類的操作也就不能進(jìn)行,這可能會(huì)有潛在的危險(xiǎn)。另外我們查看一下QWidget的mousePressEvent()函數(shù)的實(shí)現(xiàn):

  1. void QWidget::mousePressEvent(QMouseEvent *event)  
  2. {  
  3.         event->ignore();  
  4.         if ((windowType() == Qt::Popup)) {  
  5.                 event->accept();  
  6.                 QWidget* w;  
  7.                 while ((w = qApp->activePopupWidget()) && w != this){  
  8.                         w->close();  
  9.                         if (qApp->activePopupWidget() == w) // widget does not want to dissappear  
  10.                                 w->hide(); // hide at least  
  11.                 }  
  12.                 if (!rect().contains(event->pos())){  
  13.                         close();  
  14.                 }  
  15.         }  
  16. }  

請(qǐng)注意第一條語句,如果所有子類都沒有覆蓋mousePressEvent函數(shù),這個(gè)事件會(huì)在這里被忽略掉,這暗示著這個(gè)組件不關(guān)心這個(gè)事件,這個(gè)事件就可能被傳遞給其父組件。

不過,事情也不是絕對(duì)的。在一個(gè)情形下,我們必須使用accept()和ignore()函數(shù),那就是在窗口關(guān)閉的時(shí)候。如果你在窗口關(guān)閉時(shí)需要有個(gè)詢問對(duì)話框,那么就需要這么去寫:

  1. void MainWindow::closeEvent(QCloseEvent * event)  
  2. {  
  3.         if(continueToClose()) {  
  4.                 event->accept();  
  5.         } else {  
  6.                 event->ignore();  
  7.         }  
  8. }  
  9. bool MainWindow::continueToClose()  
  10. {  
  11.         if(QMessageBox::question(this,  
  12.                                             tr("Quit"),  
  13.                                             tr("Are you sure to quit this application?"),  
  14.                                             QMessageBox::Yes | QMessageBox::No,  
  15.                                             QMessageBox::No)  
  16.                 == QMessageBox::Yes) {  
  17.                 return true;  
  18.         } else {  
  19.                 return false;  
  20.         }  

這樣,我們經(jīng)過詢問之后才能正常退出程序

今天要說的是event()函數(shù)。記得之前曾經(jīng)提到過這個(gè)函數(shù),說在事件對(duì)象創(chuàng)建完畢后,Qt將這個(gè)事件對(duì)象傳遞給QObject的event()函數(shù)。event()函數(shù)并不直接處理事件,而是將這些事件對(duì)象按照它們不同的類型,分發(fā)給不同的事件處理器(event handler)。

event()函數(shù)主要用于事件的分發(fā),所以,如果你希望在事件分發(fā)之前做一些操作,那么,就需要注意這個(gè)event()函數(shù)了。為了達(dá)到這種目的,我們可以重寫event()函數(shù)。例如,如果你希望在窗口中的tab鍵按下時(shí)將焦點(diǎn)移動(dòng)到下一組件,而不是讓具有焦點(diǎn)的組件處理,那么你就可以繼承QWidget,并重寫它的event()函數(shù),已達(dá)到這個(gè)目的:

  1. bool MyWidget::event(QEvent *event) {  
  2.         if (event->type() == QEvent::KeyPress) {  
  3.                 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);  
  4.                 if (keyEvent->key() == Qt::Key_Tab) {  
  5.                         // 處理Tab鍵  
  6.                         return true;  
  7.                 }  
  8.         }  
  9.  
  10.         return QWidget::event(event);  

event()函數(shù)接受一個(gè)QEvent對(duì)象,也就是需要這個(gè)函數(shù)進(jìn)行轉(zhuǎn)發(fā)的對(duì)象。為了進(jìn)行轉(zhuǎn)發(fā),必定需要有一系列的類型判斷,這就可以調(diào)用QEvent的type()函數(shù),其返回值是QEvent::Type類型的枚舉。我們處理過自己需要的事件后,可以直接return回去,對(duì)于其他我們不關(guān)心的事件,需要調(diào)用父類的event()函數(shù)繼續(xù)轉(zhuǎn)發(fā),否則這個(gè)組件就只能處理我們定義的事件了。

event()函數(shù)返回值是bool類型,如果傳入的事件已被識(shí)別并且處理,返回true,否則返回false。如果返回值是true,QApplication會(huì)認(rèn)為這個(gè)事件已經(jīng)處理完畢,會(huì)繼續(xù)處理事件隊(duì)列中的下一事件;如果返回值是false,QApplication會(huì)嘗試尋找這個(gè)事件的下一個(gè)處理函數(shù)。

event()函數(shù)的返回值和事件的accept()和ignore()函數(shù)不同。accept()和ignore()函數(shù)用于不同的事件處理器之間的溝通,例如判斷這一事件是否處理;event()函數(shù)的返回值主要是通知QApplication的notify()函數(shù)是否處理下一事件。為了更加明晰這一點(diǎn),我們來看看QWidget的event()函數(shù)是如何定義的:

  1. bool QWidget::event(QEvent *event) {  
  2.         switch (e->type()) {  
  3.         case QEvent::KeyPress:  
  4.                  keyPressEvent((QKeyEvent *)event);  
  5.                 if (!((QKeyEvent *)event)->isAccepted())  
  6.                         return false;  
  7.                 break;  
  8.         case QEvent::KeyRelease:  
  9.                 keyReleaseEvent((QKeyEvent *)event);  
  10.                 if (!((QKeyEvent *)event)->isAccepted())  
  11.                         return false;  
  12.                 break;  
  13.                 // more...  
  14.         }  
  15.         return true;  

QWidget的event()函數(shù)使用一個(gè)巨大的switch來判斷QEvent的type,并且分發(fā)給不同的事件處理函數(shù)。在事件處理函數(shù)之后,使用這個(gè)事件的isAccepted()方法,獲知這個(gè)事件是不是被接受,如果沒有被接受則event()函數(shù)立即返回false,否則返回true。

另外一個(gè)必須重寫event()函數(shù)的情形是有自定義事件的時(shí)候。如果你的程序中有自定義事件,則必須重寫event()函數(shù)以便將自定義事件進(jìn)行分發(fā),否則你的自定義事件永遠(yuǎn)也不會(huì)被調(diào)用。

創(chuàng)建事件過濾器和安裝事件過濾器

Qt創(chuàng)建了QEvent事件對(duì)象之后,會(huì)調(diào)用QObject的event()函數(shù)做事件的分發(fā)。有時(shí)候,你可能需要在調(diào)用event()函數(shù)之前做一些另外的操作,比如,對(duì)話框上某些組件可能并不需要響應(yīng)回車按下的事件,此時(shí),你就需要重新定義組件的event()函數(shù)。如果組件很多,就需要重寫很多次event()函數(shù),這顯然沒有效率。為此,你可以使用一個(gè)事件過濾器,來判斷是否需要調(diào)用event()函數(shù)。

QOjbect有一個(gè)eventFilter()函數(shù),用于建立事件過濾器。這個(gè)函數(shù)的簽名如下:

  1. virtual bool QObject::eventFilter ( QObject * watched, QEvent * event ) 

如果watched對(duì)象安裝了事件過濾器,這個(gè)函數(shù)會(huì)被調(diào)用并進(jìn)行事件過濾,然后才輪到組件進(jìn)行事件處理。在重寫這個(gè)函數(shù)時(shí),如果你需要過濾掉某個(gè)事件,例如停止對(duì)這個(gè)事件的響應(yīng),需要返回true。

  1. bool MainWindow::eventFilter(QObject *obj, QEvent *event)  
  2.  {  
  3.          if (obj == textEdit) {  
  4.                  if (event->type() == QEvent::KeyPress) {  
  5.                          QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);  
  6.                          qDebug() << "Ate key press" << keyEvent->key();  
  7.                          return true;  
  8.                  } else {  
  9.                          return false;  
  10.                  }  
  11.          } else {  
  12.                  // pass the event on to the parent class  
  13.                  return QMainWindow::eventFilter(obj, event);  
  14.          }  
  15.  } 

上面的例子中為MainWindow建立了一個(gè)事件過濾器。為了過濾某個(gè)組件上的事件,首先需要判斷這個(gè)對(duì)象是哪個(gè)組件,然后判斷這個(gè)事件的類型。例如,我不想讓textEdit組件處理鍵盤事件,于是就首先找到這個(gè)組件,如果這個(gè)事件是鍵盤事件,則直接返回true,也就是過濾掉了這個(gè)事件,其他事件還是要繼續(xù)處理,所以返回false。對(duì)于其他組件,我們并不保證是不是還有過濾器,于是最保險(xiǎn)的辦法是調(diào)用父類的函數(shù)。

在創(chuàng)建了過濾器之后,下面要做的是安裝這個(gè)過濾器。安裝過濾器需要調(diào)用installEventFilter()函數(shù)。這個(gè)函數(shù)的簽名如下:

  1. void QObject::installEventFilter ( QObject * filterObj ) 

這個(gè)函數(shù)是QObject的一個(gè)函數(shù),因此可以安裝到任何QObject的子類,并不僅僅是UI組件。這個(gè)函數(shù)接收一個(gè)QObject對(duì)象,調(diào)用了這個(gè)函數(shù)安裝事件過濾器的組件會(huì)調(diào)用filterObj定義的eventFilter()函數(shù)。例如,textField.installEventFilter(obj),則如果有事件發(fā)送到textField組件是,會(huì)先調(diào)用obj->eventFilter()函數(shù),然后才會(huì)調(diào)用textField.event()。

當(dāng)然,你也可以把事件過濾器安裝到QApplication上面,這樣就可以過濾所有的事件,已獲得更大的控制權(quán)。不過,這樣做的后果就是會(huì)降低事件分發(fā)的效率。

如果一個(gè)組件安裝了多個(gè)過濾器,則最后一個(gè)安裝的會(huì)最先調(diào)用,類似于堆棧的行為。

注意,如果你在事件過濾器中delete了某個(gè)接收組件,務(wù)必將返回值設(shè)為true。否則,Qt還是會(huì)將事件分發(fā)給這個(gè)接收組件,從而導(dǎo)致程序崩潰。

事件過濾器和被安裝的組件必須在同一線程,否則,過濾器不起作用。另外,如果在install之后,這兩個(gè)組件到了不同的線程,那么,只有等到二者重新回到同一線程的時(shí)候過濾器才會(huì)有效。

事件的調(diào)用最終都會(huì)調(diào)用QCoreApplication的notify()函數(shù),因此,最大的控制權(quán)實(shí)際上是重寫QCoreApplication的notify()函數(shù)。由此可以看出,Qt事件處理實(shí)際上是分層五個(gè)層次:重定義事件處理函數(shù),重定義event()函數(shù),為單個(gè)組件安裝事件過濾器,為QApplication安裝事件過濾器,重定義QCoreApplication的notify()函數(shù)。這幾個(gè)層次的控制權(quán)是逐層增大的。

小結(jié):關(guān)于QT類 Qevent事件處理過程 事件過濾器 的內(nèi)容介紹按了,希望本文對(duì)你有所幫助。

責(zé)任編輯:zhaolei 來源: 互聯(lián)網(wǎng)
相關(guān)推薦

2011-06-29 16:14:59

Qt 事件 過濾器

2011-07-04 14:00:11

QT QEvent

2021-07-05 15:22:03

Servlet過濾器客戶端

2024-01-05 09:04:35

隆過濾器數(shù)據(jù)結(jié)構(gòu)哈希函數(shù)

2011-07-01 14:20:59

Qt 事件

2011-07-01 14:14:34

Qt 事件

2024-11-04 08:45:48

布隆過濾器元數(shù)據(jù)指紋值

2009-07-08 15:30:56

Servlet過濾器

2009-07-08 16:07:04

Servlet過濾器配

2009-09-29 13:55:23

Hibernate設(shè)置

2009-07-14 09:09:08

Swing模型過濾器

2011-08-29 11:25:29

QTWebKit鼠標(biāo)

2009-06-18 10:13:00

Hibernate過濾

2025-04-21 00:50:50

2017-07-18 14:10:31

大數(shù)據(jù)Apache Flum過濾器

2009-07-08 17:33:37

Servlet過濾器

2009-09-25 15:19:44

Hibernate過濾

2023-04-14 09:01:25

2011-07-04 14:50:49

QT Event 事件

2011-07-18 10:03:18

CocoaQt
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)