Qt中事件處理的方式,最常用的就是使用事件處理器(event handler)和事件過濾器(event filter)這兩種方法。接下來,我們就來看看事件處理器和事件過濾器是怎么使用的。
事件處理器
Qt中針對每一種常見的事件類型都提供了相應的事件處理器,我們如果想捕獲某種類型的事件並進行自定義處理,那么只需要實現重寫這些事件處理器就行。常見的事件類型和對應的事件處理器如下圖所示:
用戶自定義事件定義如下:
在日常使用中,我們最常使用的鼠標事件:
新建一個基於QWidget的應用程序,在QWidget的頭文件中找到鼠標操作事件處理器虛函數如下:
我們將其在我們的QWidget子類中重寫實現:
到這里這個功能就實現了,大家看看上面的頭文件就知道這里還實現了其它類型事件的處理,其實都是一樣的思路,找到欲處理的事件類型,找到對應的事件處理器,重寫事件處理器中處理事件的方法即可。這個看起來比較簡單!
事件過濾器
Qt事件模型中一項非常強大的功能就是一個QObject實例可以監視另一個QObject實例中的事件,實現方法是在目標對象中安裝事件過濾器。
假設我們有一個Dialog控件,由一些QLineEdit控件組成。我們希望使用Space鍵得到下一個QLineEdit的輸入焦點。
一個最直接的方法是繼承QLineEdit重寫keyPressEvent()函數,當點擊了Space鍵時,調用focusNextChild():
1
2 3 4 5 6 7 8 9 10 11 |
void
MyLineEdit::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Space) { focusNextChild(); } else { QLineEdit::keyPressEvent(event); } } |
這個方法有一個最大的缺點:如果我們在窗體中使用了很多不同類型的控件(QComboBox,QSpinBox等等),我們也要繼承這些控件,重寫它們的keyPressEvent()。
一個更好的解決方法是讓Dialog監視其子控件的鍵盤事件,在監視代碼處實現以上功能。
這就是事件過濾的方法。實現一個事件過濾包括兩個步驟:
1、在目標對象上調用installEventFilter(),注冊監視對象。
2、在監視對象的eventFilter()函數中處理目標對象的事件。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include
<QDialog> class QLineEdit; class Dialog : public QDialog { Q_OBJECT public : Dialog(QWidget *parent = 0 ); ~Dialog(); protected : virtual bool eventFilter(QObject *target, QEvent *event); private : QLineEdit* firstNameEdit ; QLineEdit* lastNameEdit; QLineEdit* cityEdit; QLineEdit* phoneNumberEdit; }; |
注冊監視對象的位置是在CustomerInfoDialog的構造函數中:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Dialog::Dialog(QWidget *parent)
: QDialog(parent) { QFormLayout* formLayout = new QFormLayout; firstNameEdit = new QLineEdit(); lastNameEdit = new QLineEdit(); cityEdit = new QLineEdit(); phoneNumberEdit = new QLineEdit(); formLayout->addRow(tr( "&FirstName:" ), firstNameEdit); formLayout->addRow(tr( "&LastName:" ), lastNameEdit); formLayout->addRow(tr( "&City:" ), cityEdit); formLayout->addRow(tr( "&PhoneNumber:" ), phoneNumberEdit); setLayout(formLayout); // 給QLineEdit安裝事件過濾器 firstNameEdit->installEventFilter( this ); lastNameEdit->installEventFilter( this ); cityEdit->installEventFilter( this ); phoneNumberEdit->installEventFilter( this ); } |
事件過濾器注冊后,發送到firstNameEdit,lastNameEdit,cityEdit,phoneNumberEdit控件的事件首先到達CustomerInfoDialog::eventFilter()函數,然后在到達最終的目的地。
下面是eventFilter()函數的代碼:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
bool
Dialog::eventFilter(QObject *target, QEvent *event) { if (target == firstNameEdit || target == lastNameEdit || target == cityEdit || target == phoneNumberEdit) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast <QKeyEvent *>(event); if (keyEvent->key() == Qt::Key_Space) { focusNextChild(); return true ; } } } return QDialog::eventFilter(target, event); } |
首先,我們看是目標控件是否為QLineEdit,如果事件為鍵盤事件,把QEvent轉換為QKeyEvent,確定被敲擊的鍵。如果為Space鍵,調用focusNextChild(),把焦點交給下一個控件,返回true通知Qt已經處理了這個事件,如果返回false,Qt將會把事件傳遞給目標控件,把一個空格字符插入到QLineEdit中。