Qt 將事件封裝為QEvent實例之後,會呼叫QObject的event()方法並將QEvent實例傳送給它,在某些情況下,您希望物件在執行event ()處理事件之前,先對一些事件進行處理或過濾,然後再決定是否呼叫event()方法,這個時 候您就可以使用事件過濾器。
以 事件接 受與否、event() 方法 中所談及的,對QWidget按鍵事件的Tab鍵處理而言,如果您的圖形介面中有很多的元件,每個圖型元件都要如當中的範例重新定義event()方法, 顯然是非常沒有效率且沒什麼維護性的方法。
您可以自定義一個物件繼承QObject(或其子類別),重新定義它的eventFilter()方法,例如您自定義了一個FilterObject,您 希望Tab鍵可以用來將焦點轉移至下一個子元件:
bool
FilterObject::eventFilter(QObject *object, QEvent *event) {
if(event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Tab) {
// 處理Tab鍵
return true;
}
}
return false;
}
if(event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Tab) {
// 處理Tab鍵
return true;
}
}
return false;
}
eventFilter()的object參數表示事件發生的來源物件,eventFilter()若傳回false,則安裝該事件過濾器的物件之event()就會 繼續執行,若 傳回true,則安裝該事件過濾器的物件之event()方法就不會被執行,由此進行事件的攔截處理。
要為指定的物件安裝事件過濾器,可以使用物件的installEventFilter()方法,例如:
QLineEdit *nameEdit = new QLineEdit;
QLineEdit *addressEdit = new QLineEdit;
...
FilterObject filter = new FilterObject;
...
nameEdit->installEventFilter(filter);
addressEdit->installEventFilter(filter);
....
QLineEdit *addressEdit = new QLineEdit;
...
FilterObject filter = new FilterObject;
...
nameEdit->installEventFilter(filter);
addressEdit->installEventFilter(filter);
....
您也可以將事件過濾器安裝在QApplication,在任何的事件發生後呼叫每個物件的event()方法之 前,會先經過事件過濾器,這給您更多控制應用程式事件的能力。
Qt 的事件迴圈與sendEvent()方法會呼叫QCoreApplication(QApplication的父類別)的notify()以分派事件,如果您想要完全控制Qt應用程式的事件,則可以重新定義 notify()方法。
到這邊,可以看出Qt事件處理的五個層次:重新定義事件處理者、重新定義event()方法、為個別物件安裝事件過濾器、為QApplication安裝 事件過濾器,重新定義QCoreApplication的notify()方法。