Qt入門(8)——事件和事件過濾器

尹成發表於2014-09-30
在Qt裡,一個事件是繼承自QEvent的物件。事件通過呼叫QObject::event(),被髮送到繼承自 QObject 的物件。事件傳送就是一個事件已經產生,由 QEvent正好去表達,且QObject 需要去迴應。多數事件針對 QWidget和他的子類的,此外還有些不和圖形相關的重要事件,比如,套接字啟用,——某種被用於QSocketNotifier運作的事件。


某些事件來自視窗系統,如QMouseEvent,某些來自其他源頭,如QTimerEvent,而某些來自應用程式。Qt一視同仁,因此像通常一樣,你可以準確地傳送事件,這和Qt自己的事件迴圈所作的方式一樣。


多數事件型別具有特定的類,最常見的QResizeEvent、QPaintEvent、QMouseEvent、QKeyEvent和QCloseEvent。有很多別的,差不多40種左右,但大都是相當零碎。


每個類派生自QEvent且新增事件特定的函式;例如,QResizeEvent。在QResizeEvent中,就被加入了QResizeEvent::size()和QResizeEvent::oldSize()。


某些類支援多種事件型別。QMouseEvent支援滑鼠移動、按壓、粘滯按壓、拖拽、點選、右按壓,等等。


因為程式需要在多變且複雜的方式下作用,Qt的事件派發機制就是靈活的。QApplication::notify() 的文件扼要地敘述其整個來龍去脈,我們揭示在這裡的內容滿足99%的應用。


對於事件去被派發的正常的辦法是呼叫一個虛擬函式。如,QPaintEvent通過呼叫QWidget::paintEvent()被使用。這個虛擬函式負責引起適當的響應,一般是重畫視窗部件。


有時,並不存在一個特定事件函式,或者特定事件功能不足。最普通的例如按下tab鍵。正常情況下,被QWidget看成是去移動 鍵盤焦點,但少數視窗部件 需要自行解釋。


這些物件能重新實現QObject::event(),按常規事件處理,以及要麼在通常的處理之前,或之後處理,或完全重寫。一個與眾不同的的視窗部件,它解釋了tab,也含有一個該應用特定的可能包含的自定製事件:


  bool MyClass:event( QEvent * e ) {
      if ( e->type() == QEvent::KeyPress ) {
          QKeyEvent * ke = (QKeyEvent*) e;
          if ( ke->key() == Key_Tab ) {
              // 這裡是特定的tab處理
              k->accept();
              return TRUE;
          }
      } else if ( e->type() >= QEvent::User ) {
          QCustomEvent * c = (QCustomEvent*) e;
          // 這裡是自定義事件處理
          return TRUE;
      }
      QWidget::event( e );
  }
更一般的,一個物件需要去考慮其它的事件。Qt用QObject::installEventFilter()支援這個目的(相應的有移除)。如,對話方塊通常要為某些視窗部件去過濾按鍵,比如,去修改Return鍵的處理。


一個事件過濾器在目標物件處理之前得以去處理事件。過濾器的QObject::eventFilter()實現被呼叫,它可以接受或丟棄過濾,也可容許或拒絕進一步去處理事件。如果所有的事件過濾器允許進一步的處理事件,事件自己就被送達目標物件。如果它們之一停止處理,目標和任何後面的事件過濾器根本就對該事件一無所知了。


整個應用程式中過濾所有的事件也是可能的,通過在QApplication上安裝一個事件過濾器。這裡有QToolTip為了處理全部滑鼠和鍵盤行為的實作。這個功能相當強大,但其在整個應用中也拖慢了每單個事件的派送,因此最好避免這種應用方式。


全域性事件過濾器在物件特定的過濾器前被呼叫。


許多應用程式都要建立和傳送他們自己的事件。


建立一種內建型別的事件是非常簡單的:建立一個相應的型別的物件,然後呼叫QApplication::sendEvent()或者QApplication::postEvent()。


sendEvent() 立即處理事件——當sendEvent() 返回,(事件過濾器和)物件已經處理過事件了。對於很多事件類,呼叫isAccepted()函式,他告知你該事件能否被目前呼叫的處理者所接受或者拒絕。


postEvent()投送事件於一個佇列,以使能延遲派發。在下次Qt的主事件迴圈執行,他派發全部事件,帶有些優化。舉例,若有數個resize事件,它們就被壓縮到一個。對於paint事件同樣如此:QWidget::update()呼叫 postEvent(),最小化閃屏和避免多次重畫,以增加速度。


postEvent()在物件初始化期間常常被使用,因為在物件完成初始化後,投送的訊息會被很快派發。


去建立一個自定義型別的事件,你需要定義一個事件號,其必須大於QEvent::User,可能你也需要從QCustomEvent去派生,為了傳遞有關你的自定義事件的特性。看QCustomEvent的文件瞭解細節。

相關文章