【Qt筆記】event()

前面的章節中咱們曾經提到event()函數。事件對象建立完畢後,Qt 將這個事件對象傳遞給QObjectevent()函數。event()函數並不直接處理事件,而是將這些事件對象按照它們不一樣的類型,分發給不一樣的事件處理器(event handler)。函數

 

如上所述,event()函數主要用於事件的分發。因此,若是你但願在事件分發以前作一些操做,就能夠重寫這個event()函數了。例如,咱們但願在一個QWidget組件中監聽 tab 鍵的按下,那麼就能夠繼承QWidget,並重寫它的event()函數,來達到這個目的:測試

bool CustomWidget::event(QEvent *e)
{
    if (e->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
        if (keyEvent->key() == Qt::Key_Tab) {
            qDebug() << "You press tab.";
            return true;
        }
    }
    return QWidget::event(e);
}

CustomWidget是一個普通的QWidget子類。咱們重寫了它的event()函數,這個函數有一個QEvent對象做爲參數,也就是須要轉發的事件對象。函數返回值是 bool 類型。若是傳入的事件已被識別而且處理,則須要返回 true,不然返回 false。若是返回值是 true,而且,該事件對象設置了accept(),那麼 Qt 會認爲這個事件已經處理完畢,不會再將這個事件發送給其它對象,而是會繼續處理事件隊列中的下一事件。注意,在event()函數中,調用事件對象的accept()ignore()函數是沒有做用的,不會影響到事件的傳播。code

咱們能夠經過使用QEvent::type()函數能夠檢查事件的實際類型,其返回值是QEvent::Type類型的枚舉。咱們處理過本身感興趣的事件以後,能夠直接返回 true,表示咱們已經對此事件進行了處理;對於其它咱們不關心的事件,則須要調用父類的event()函數繼續轉發,不然這個組件就只能處理咱們定義的事件了。爲了測試這一種狀況,咱們能夠嘗試下面的代碼:對象

bool CustomTextEdit::event(QEvent *e)
{
    if (e->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
        if (keyEvent->key() == Qt::Key_Tab) {
            qDebug() << "You press tab.";
            return true;
        }
    }
    return false;
}

CustomTextEditQTextEdit的一個子類。咱們重寫了其event()函數,卻沒有調用父類的同名函數。這樣,咱們的組件就只能處理 Tab 鍵,再也沒法輸入任何文本,也不能響應其它事件,好比鼠標點擊以後也不會有光標出現。這是由於咱們只處理的KeyPress類型的事件,而且若是不是KeyPress事件,則直接返回 false,鼠標事件根本不會被轉發,也就沒有了鼠標事件。繼承

經過查看QObject::event()的實現,咱們能夠理解,event()函數同前面的章節中咱們所說的事件處理器有什麼聯繫:隊列

//!!! Qt5
bool QObject::event(QEvent *e)
{
    switch (e->type()) {
    case QEvent::Timer:
        timerEvent((QTimerEvent*)e);
        break;

    case QEvent::ChildAdded:
    case QEvent::ChildPolished:
    case QEvent::ChildRemoved:
        childEvent((QChildEvent*)e);
        break;
    // ...
    default:
        if (e->type() >= QEvent::User) {
            customEvent(e);
            break;
        }
        return false;
    }
    return true;
}

這是 Qt 5 中QObject::event()函數的源代碼(Qt 4 的版本也是相似的)。咱們能夠看到,同前面咱們所說的同樣,Qt 也是使用QEvent::type()判斷事件類型,而後調用了特定的事件處理器。好比,若是event->type()返回值是QEvent::Timer,則調用timerEvent()函數。能夠想象,QWidget::event()中必定會有以下的代碼:事件

switch (event->type()) {
    case QEvent::MouseMove:
        mouseMoveEvent((QMouseEvent*)event);
        break;
    // ...
}

事實也的確如此。timerEvent()mouseMoveEvent()這樣的函數,就是咱們前面章節所說的事件處理器 event handler。也就是說,event()函數中實際是經過事件處理器來響應一個具體的事件。這至關於event()函數將具體事件的處理「委託」給具體的事件處理器。而這些事件處理器是 protected virtual 的,所以,咱們重寫了某一個事件處理器,便可讓 Qt 調用咱們本身實現的版本。get

由此能夠見,event()是一個集中處理不一樣類型的事件的地方。若是你不想重寫一大堆事件處理器,就能夠重寫這個event()函數,經過QEvent::type()判斷不一樣的事件。鑑於重寫event()函數須要十分當心注意父類的同名函數的調用,一不留神就可能出現問題,因此通常仍是建議只重寫事件處理器(固然,也必須記得是否是應該調用父類的同名處理器)。這其實暗示了event()函數的另一個做用:屏蔽掉某些不須要的事件處理器。正如咱們前面的CustomTextEdit例子看到的那樣,咱們建立了一個只能響應 tab 鍵的組件。這種做用是重寫事件處理器所不能實現的。it

相關文章
相關標籤/搜索