在 Qt 中事件是對象,派生自抽象 QEvent 類,錶示應用程序中發生的事情,或作為應用程序需要知道的有關外部活動的結果。事件可以被接收並處理通過任何實例化的 QObject 子類,但它們尤其與 Widget 相關。本文檔描述在典型應用程序中,如何交付和處理事件。
當事件齣現時,Qt 創建事件對象來錶示它,通過構造實例化的適當 QEvent 子類,並把其交付給特定實例化的 QObject (或它的某個子類) 通過調用其 event() 函數。
此函數不處理事件本身;根據交付的事件類型,它調用用於特定事件類型的事件處理程序,並根據事件是被接受還是忽略發送響應。
某些事件,譬如 QMouseEvent and QKeyEvent ,來自窗口係統;某些,譬如 QTimerEvent ,來自其它源;某些來自應用程序本身。
大多數事件類型都擁有特殊類,尤其是 QResizeEvent , QPaintEvent , QMouseEvent , QKeyEvent ,和 QCloseEvent 。各類子類化 QEvent 並添加特定事件函數。例如, QResizeEvent 添加 size() and oldSize() 以使 Widget 能夠探索它們的維度是如何改變的。
有些類支持,多種實際事件類型。 QMouseEvent 支持鼠標按鍵按下、雙擊、移動、及其它相關操作。
各事件都擁有關聯類型,定義在 QEvent::Type ,且這可以用作運行時類型信息的方便源,以快速確定給定事件對象是從哪個子類構造的。
由於程序需要以各種且復雜的方式作齣反應,Qt 的事件交付機製是很靈活的。文檔編製對於 QCoreApplication::notify () 將簡潔敘述整個故事; Qt 季刊 文章 從另一角度看事件 不那麼簡潔地重講瞭它。在這裏,我們將對 95% 的應用程序進行足夠闡述。
用於交付事件的正常方式,是通過調用虛函數。例如, QPaintEvent 的交付是通過調用 QWidget::paintEvent ()。此虛函數負責適當應對,通常是通過重新描繪 Widget。若在虛函數實現中不履行所有必要工作,可能需要調用基類實現。
例如,以下代碼處理自定義復選框 Widget 中的鼠標左鍵點擊,同時把所有其它按鈕點擊傳遞給基 QCheckBox 類:
void MyCheckBox::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { // handle left mouse button here } else { // pass on other buttons to base class QCheckBox::mousePressEvent(event); } }
若想要替換基類函數,自己必須實現一切。不管怎樣,若隻想擴展基類功能,則實現想要的,並調用基類以獲得不想處理的任何情況的默認行為。
有時,沒有這種特定事件函數,或特定事件函數不夠。最常見範例涉及 Tab 鍵按下。通常, QWidget 攔截這些以移動鍵盤聚焦,但一些 Widget 本身需要 Tab 鍵。
這些對象可以重實現 QObject::event ()、一般事件處理程序、及在之前履行它們的事件處理 (或通常在之後處理,或它們可以完全替換函數)。非常不尋常的 Widget,既解釋 Tab 又擁有特定應用程序的自定義事件,可能包含以下 event() 函數:
bool MyWidget::event(QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast<QKeyEvent *>(event); if (ke->key() == Qt::Key_Tab) { // special tab handling here return true; } } else if (event->type() == MyCustomEventType) { MyCustomEvent *myEvent = static_cast<MyCustomEvent *>(event); // custom event handling here return true; } return QWidget::event(event); }
注意,
QWidget::event
() 對於所有未處理情況仍被調用,並返迴事件是否被處理的指示值;
true
值阻止把事件,發送給其它對象。
Sometimes an object needs to look at, and possibly intercept, the events that are delivered to another object. For example, dialogs commonly want to filter key presses for some widgets; for example, to modify Return-key handling.
The QObject::installEventFilter () function enables this by setting up an 事件過濾器 , causing a nominated filter object to receive the events for a target object in its QObject::eventFilter () function. An event filter gets to process events before the target object does, allowing it to inspect and discard the events as required. An existing event filter can be removed using the QObject::removeEventFilter () 函數。
When the filter object's
eventFilter()
implementation is called, it can accept or reject the event, and allow or deny further processing of the event. If all the event filters allow further processing of an event (by each returning
false
), the event is sent to the target object itself. If one of them stops processing (by returning
true
), the target and any later event filters do not get to see the event at all.
bool FilterObject::eventFilter(QObject *object, QEvent *event) { if (object == target && event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); if (keyEvent->key() == Qt::Key_Tab) { // Special tab handling return true; } else return false; } return false; }
The above code shows another way to intercept Tab key press events sent to a particular target widget. In this case, the filter handles the relevant events and returns
true
to stop them from being processed any further. All other events are ignored, and the filter returns
false
to allow them to be sent on to the target widget, via any other event filters that are installed on it.
It is also possible to filter all events for the entire application, by installing an event filter on the QApplication or QCoreApplication object. Such global event filters are called before the object-specific filters. This is very powerful, but it also slows down event delivery of every single event in the entire application; the other techniques discussed should generally be used instead.
Many applications want to create and send their own events. You can send events in exactly the same ways as Qt's own event loop by constructing suitable event objects and sending them with QCoreApplication::sendEvent () 和 QCoreApplication::postEvent ().
sendEvent() processes the event immediately. When it returns, the event filters and/or the object itself have already processed the event. For many event classes there is a function called isAccepted() that tells you whether the event was accepted or rejected by the last handler that was called.
postEvent() posts the event on a queue for later dispatch. The next time Qt's main event loop runs, it dispatches all posted events, with some optimization. For example, if there are several resize events, they are compressed into one. The same applies to paint events: QWidget::update () 調用 postEvent() , which eliminates flickering and increases speed by avoiding multiple repaints.
postEvent() is also used during object initialization, since the posted event will typically be dispatched very soon after the initialization of the object is complete. When implementing a widget, it is important to realize that events can be delivered very early in its lifetime so, in its constructor, be sure to initialize member variables early on, before there's any chance that it might receive an event.
To create events of a custom type, you need to define an event number, which must be greater than QEvent::User , and you may need to subclass QEvent in order to pass specific information about your custom event. See the QEvent 文檔編製進一步瞭解細節。