事件接受與否、event() 方法


不 同類型的事件,都有對應的事件處理函式,它們接受QEvent的特定子類別實例作為引數,像是下例中mousePressEvent()事件處理函式上的 QMouseEvent,您可以針對事件的某些狀況作特定處理,而其它未處理的狀況,則呼叫父類別對應的的事件處理函式,讓父類別預先定義的事件處理可以 完成:
void CustomLabel::mousePressEvent(QMouseEvent *event) {
     if (event->button() == Qt::LeftButton) {
         // 處理左鍵按下
         // ....
     } else {
         // 由父類別所定義的事件處理函式來事件
        
QLabel::mousePressEvent(event);
     }
}
void CustomLabel::mouseReleaseEvent(QMouseEvent *event) {
    // 滑鼠放開事件處理....
}

事實上,每個可傳播的事件都有accept()與igore()兩個方法,用以告知Qt應用程式,這個事件處理者是否接受或忽略此 一事件,如果事件處理者中呼叫事件的accept(),則事件不會再進一步傳播,若呼叫了ignore(),則Qt應用程式會嘗試尋找另一個事件的接受者,您可以藉由isAccepted()方法得知事件是否被接受。

一般來說,除了QCloseEvent之外,很少直接呼叫accept()或ignore(),如果您接受事件,則在事件處理者當中實作對事件的處理(如上例的if陳述句),如果您不 接受事件,則直接呼叫父類別的事件實作(如上例的else陳述句),對於QWidget來說,預設的實作是:
void QWidget::keyPressEvent(QKeyEvent *event) {
    event->ignore();
}

由於QWidget預設的實作是呼叫ignore(),這讓事件可以向父元件傳播。

QCloseEvent則建議直接呼叫accept()與ignore(),accept()方法會繼續關閉的操作,ignore()則會取消關閉的操作:
void MainWindow::closeEvent(QCloseEvent *event) {
    if (continueToClose()) {
        event->accept();
    } else {
        event->ignore();
    }
}

QObject的event()方法通常用於分派事件,但在某些情況下,您希望在事件分派給其它事件處理者之 前,先行作一些處理,則可以重新定義event()方法,例如在視窗程式中,Tab鍵按下時希望其將焦點移至下一個圖型元件,而不是直接讓目前焦點的圖形 元件直接處理Tab鍵,則您可以在繼承QWidget子類別時,重新定義其event()方法,例如:
bool CustomWidget::event(QEvent *event) {
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if (keyEvent->key() == Qt::Key_Tab) {
            // 處理Tab鍵
            return true;
        }
    }

    return QWidget::event(event);
}

在執行時期想要知道所取得之QEvent類型,可以使用QEvent的type()方法取得常數值,並與QEvent::Type作比對。

事件若順利處理完畢,則要傳回true,表示這個事件被接受並處理,QApplication可以繼續事件佇列中的下一個事件處理,若傳回false,則QApplication嘗試尋找下一個可以處理事件的方法。 您不用呼叫事件的accept()或ignore(),這也沒有意義,accept()或ignore()是用來在特定的事件處理者之間作溝通,而 event()的true或false,是用來告知QApplication的notify()方法是否處理下一事件,以QWidget的event() 實作來說,它是根據事件的isAccepted()來判斷該傳回true或false:
bool QWidget::event(QEvent *event) {
    switch (e->type()) {
    case QEvent::KeyPress:
         keyPressEvent((QKeyEvent *)event);
        if (!((QKeyEvent *)event)->isAccepted())
            return false;
        break;
    case QEvent::KeyRelease:
        keyReleaseEvent((QKeyEvent *)event);
        if (!((QKeyEvent *)event)->isAccepted())
            return false;
        break;
        ...
    }
    return true;
}

另一個重新定義event()的情況是自訂QCustomEvent子類型時,您可以將之分派給其它函式或直接在event()中處理,例如:
bool CustomWidget::event(QEvent *event) {
    if (event->type() == MyCustomEventType) {
        CustomEvent *myEvent = static_cast<CustomEvent *>(event);
        // 對自訂事件的處理,或呼叫其它函式來處理事件
        return true;
    }

    return QWidget::event(event);
}

自訂事件必須是QCustomEvent的子類別,您也可以直接實作customEvent()方法來處理自訂事件,詳可參考
自訂與傳送事件