Qt建立了QEvent事件對象以後,會調用QObject的event()函數作事件的分發。有時候,你可能須要在調用event()函數以前作一些另外的操做,好比,對話框上某些組件可能並不須要響應回車按下的事件,此時,你就須要從新定義組件的event()函數。若是組件不少,就須要重寫不少次event()函數,這顯然沒有效率。爲此,你可使用一個事件過濾器,來判斷是否須要調用event()函數。
QOjbect有一個eventFilter()函數,用於創建事件過濾器。這個函數的簽名以下:
virtual
bool QObject::eventFilter ( QObject * watched, QEvent *
event )
若是watched對象安裝了事件過濾器,這個函數會被調用並進行事件過濾,而後才輪到組件進行事件處理。在重寫這個函數時,若是你須要過濾掉某個事件,例如中止對這個事件的響應,須要返回true。
bool MainWindow::eventFilter(QObject *obj, QEvent *
event)
![](http://static.javashuo.com/static/loading.gif)
{
if (obj == textEdit) {
if (
event->type() == QEvent::KeyPress) {
![](http://static.javashuo.com/static/loading.gif)
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(
event);
![](http://static.javashuo.com/static/loading.gif)
qDebug() <<
"Ate key press" << keyEvent->key();
return
true;
![](http://static.javashuo.com/static/loading.gif)
}
else {
return
false;
![](http://static.javashuo.com/static/loading.gif)
}
![](http://static.javashuo.com/static/loading.gif)
}
else {
// pass the event on to the parent class
return QMainWindow::eventFilter(obj,
event);
![](http://static.javashuo.com/static/loading.gif)
}
![](http://static.javashuo.com/static/loading.gif)
}
上面的例子中爲MainWindow創建了一個事件過濾器。爲了過濾某個組件上的事件,首先須要判斷這個對象是哪一個組件,而後判斷這個事件的類型。例如,我不想讓textEdit組件處理鍵盤事件,因而就首先找到這個組件,若是這個事件是鍵盤事件,則直接返回true,也就是過濾掉了這個事件,其餘事件仍是要繼續處理,因此返回false。對於其餘組件,咱們並不保證是否是還有過濾器,因而最保險的辦法是調用父類的函數。
在建立了過濾器以後,下面要作的是安裝這個過濾器。安裝過濾器須要調用installEventFilter()函數。這個函數的簽名以下:
void QObject::installEventFilter ( QObject * filterObj )
這個函數是QObject的一個函數,所以能夠安裝到任何QObject的子類,並不只僅是UI組件。這個函數接收一個QObject對象,調用了這個函數安裝事件過濾器的組件會調用filterObj定義的eventFilter()函數。例如,textField.installEventFilter(obj),則若是有事件發送到textField組件是,會先調用obj->eventFilter()函數,而後纔會調用textField.event()。
固然,你也能夠把事件過濾器安裝到QApplication上面,這樣就能夠過濾全部的事件,已得到更大的控制權。不過,這樣作的後果就是會下降事件分發的效率。
若是一個組件安裝了多個過濾器,則最後一個安裝的會最早調用,相似於堆棧的行爲。
注意,若是你在事件過濾器中delete了某個接收組件,務必將返回值設爲true。不然,Qt仍是會將事件分發給這個接收組件,從而致使程序崩潰。 事件過濾器和被安裝的組件必須在同一線程,不然,過濾器不起做用。另外,若是在install以後,這兩個組件到了不一樣的線程,那麼,只有等到兩者從新回到同一線程的時候過濾器纔會有效。 事件的調用最終都會調用QCoreApplication的notify()函數,所以,最大的控制權其實是重寫QCoreApplication的notify()函數。由此能夠看出,Qt的事件處理其實是分層五個層次:重定義事件處理函數,重定義event()函數,爲單個組件安裝事件過濾器,爲QApplication安裝事件過濾器,重定義QCoreApplication的notify()函數。這幾個層次的控制權是逐層增大的。