2010年9月13日 星期一

Qt4 學習筆記(六):Event Accept or Ignore and event() method

  • Event Accept or Ignore and event() method
不同類型的事件,都有對應的事件處理函式,它們接受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來說,預設的實作如下,由於QWidget預設的實作是呼叫ignore(),這讓事件可以向父元件傳播。

void QWidget::keyPressEvent(QKeyEvent *event) {
    event->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);
}
Notes:
      if (event->type() == QEvent::KeyPress)
    1. 在執行時期想要知道所取得之QEvent類型,可以使用QEvent的type()方法取得常數值,並與QEvent::Type作比對。
    2. QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
    3. 對event作強制形態轉換為QKeyEvent並宣告為keyEvent,新的keyEvent可以使用QKeyEvent的成員。

事件若順利處理完畢,則要傳回true,表示這個事件被接受並處理,QApplication可以繼續事件佇列中的下一個事件處理,若傳回false,則QApplication嘗試尋找下一個可以處理事件的方法。不用透過呼叫事件的accept()或ignore(),這也沒有意義,accept()或ignore()是用來在特定的事件處理者之間作溝通,而event()的true或false,是用來告知QApplication的notify()方法是否處理下一事件,以QWidget的event()實作來說,它是根據事件的isAccepted()來判斷該傳回true或false。

bool QWidget::event(QEvent *event) {
    switch (event->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()的情況是自訂CustomEvent子類型時,可以將之分派給其它函式或直接在event()中處理,自訂事件必須是CustomEvent的子類別,也可以直接實作customEvent()方法來處理自訂事件,例如:
bool CustomWidget::event(QEvent *event) {
    if (event->type() == MyCustomEventType) {
        CustomEvent *myEvent = static_cast<CustomEvent *>(event);
        // 對自訂事件的處理,或呼叫其它函式來處理事件
        return true;
    }
    return QWidget::event(event);
}

本文參考自"良葛格:Qt4學習筆記"

0 意見: