Qt 事件系統(tǒng) Qt是事件驅(qū)動的, 程序每個動作都是由某個事件所觸發(fā)。 Qt事件的類型很多,我們可以通過查看Qt的 manual中的Event System 和 QEvent 來獲得各個事件的詳細(xì)信息。 為了完整起見,一份Qt4.6的事件列表附在本文后面。 事件來源 Spontaneous events(自發(fā)事件) 從系統(tǒng)得到的消息,比如鼠標(biāo)按鍵,鍵盤按鍵等。Qt事件循環(huán)的時候讀取這些事件,轉(zhuǎn)化為QEvent后依次處理 Posted events 有Qt或應(yīng)用程序產(chǎn)生,放入消息隊(duì)列 QCoreApplication::postEvent() Sent events 由Qt或應(yīng)用程序產(chǎn)生,不放入隊(duì)列,直接被派發(fā)和處理 QCoreApplication::sendEvent() 比如考慮重繪事件處理函數(shù) paintEvent(),3種事件都能使得該函數(shù)被調(diào)用: 當(dāng)窗口被其他窗口覆蓋后,再次重新顯示時,系統(tǒng)將產(chǎn)生 spontaneous 事件來請求重繪 當(dāng)我們調(diào)用 update() 時,產(chǎn)生的是 Posted 事件 當(dāng)我們調(diào)用 repaint() 時,產(chǎn)生的是 Sent 事件 事件派發(fā)事件循環(huán) while (!exit_was_called) { while (!posted_event_queue_is_empty) { process_next_posted_event(); } while (!spontaneous_event_queue_is_empty) { process_next_spontaneous_event(); } while (!posted_event_queue_is_empty) { process_next_posted_event(); } } 先處理Qt事件隊(duì)列中的事件,直至為空 再處理系統(tǒng)消息隊(duì)列中的消息,直至為空 在處理系統(tǒng)消息的時候會產(chǎn)生新的Qt事件,需要對其再次進(jìn)行處理 不通過事件循環(huán) sendEvent的事件派發(fā)不通過事件循環(huán)。QApplication::sendEvent()是通過調(diào)用QApplication::notify(),直接進(jìn)入了事件的派發(fā)和處理環(huán)節(jié),是同步的。 sendEvent與postEvent的使用 兩個函數(shù)都是接受一個 QObject * 和一個 QEvent * 作為參數(shù)。 postEvent 的 event 必須分配在 heep 上。用完后會被Qt自動刪除 sendEvent 的 event 必須分配在 stack 上。 例子(發(fā)送X按鍵事件到mainWin): QApplication::postEvent(mainWin, new QKeyEvent(QEvent::KeyPress, Key_X, 'X', 0)); QKeyEvent event(QEvent::KeyPress, Key_X, 'X', 0); QApplication::sendEvent(mainWin, &event); notify 所有的事件都最終通過 notify 派發(fā)到相應(yīng)的對象中。 bool QCoreApplication::notify ( QObject * receiver, QEvent * event )事件過濾 看看notify()調(diào)用的內(nèi)部函數(shù)notify_helper()的源碼部分: 先通過 Applicaton 安裝的過濾器 如果未被過濾,再通過 receiver 安裝的過濾器 如果仍未被過濾,才調(diào)用 receiver->event() 函數(shù)進(jìn)行派發(fā) /*!\internal Helper function called by notify() */ bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event) { // send to all application event filters if (sendThroughApplicationEventFilters(receiver, event)) return true; // send to all receiver event filters if (sendThroughObjectEventFilters(receiver, event)) return true; // deliver the event return receiver->event(event); } 事件在傳遞到對象之前(調(diào)用obj->event()函數(shù)之前),要先能通過 Applicaton 和 obj 安裝的過濾器,那么過濾器是怎么安裝的: 首先QObject中有一個類型為QObjectList的成員變量,名字為eventFilters 當(dāng)某個QObject安裝了事件過濾器之后, 它會將filterObj的指針保存在eventFilters中 monitoredObj->installEventFilter(filterObj); 在事件到達(dá)QObject::event()函數(shù)之前,會先查看該對象的eventFilters列表, 如果非空, 就先調(diào)用列表中對象的eventFilter()函數(shù). bool QObject::eventFilter ( QObject * watched, QEvent * event ) 事件過濾器函數(shù)eventFilter()返回值是bool型 如果返回true, 則表示該事件已經(jīng)被處理完畢, Qt將直接返回, 進(jìn)行下一事件的處理 如果返回false, 事件將接著被送往剩下的事件過濾器或是目標(biāo)對象進(jìn)行處理 對于 QCoreApplication ,由于也是QObject 派生類,安裝過濾器方式與前述相同。 事件轉(zhuǎn)發(fā) 對于某些類別的事件, 如果在整個事件的派發(fā)過程結(jié)束后還沒有被處理, 那么這個事件將會向上轉(zhuǎn)發(fā)給它的父widget, 直到最頂層窗口. 如何判斷一個事件是否被處理了呢? (有兩個層次) QApplication::notify(), QObject::eventFilter(), QObject::event() 通過返回bool值來表示是否已處理. “真”表示已經(jīng)處理, “假”表示事件需要繼續(xù)傳遞 另一種是調(diào)用QEvent::ignore() 或 QEvent::accept() 對事件進(jìn)行標(biāo)識,accept表示事件被處理 為清楚起見,貼一點(diǎn)Qt的源碼(來自 QApplication::notify()): case QEvent::ToolTip: case QEvent::WhatsThis: case QEvent::QueryWhatsThis: { QWidget* w = static_cast<QWidget *>(receiver); QHelpEvent *help = static_cast<QHelpEvent*>(e); QPoint relpos = help->pos(); bool eventAccepted = help->isAccepted(); while (w) { QHelpEvent he(help->type(), relpos, help->globalPos()); he.spont = e->spontaneous(); res = d->notify_helper(w, w == receiver ? help : &he); e->spont = false; eventAccepted = (w == receiver ? help : &he)->isAccepted(); if ((res && eventAccepted) || w->isWindow()) break; relpos += w->pos(); w = w->parentWidget(); } help->setAccepted(eventAccepted); } break; 這兒顯示了對 WhatsThis 事件的處理:先派發(fā)給 w,如果事件被accepted 或已經(jīng)是頂級窗口,則停止;否則獲取w的父對象,繼續(xù)派發(fā)。 事件處理 重新實(shí)現(xiàn)一個特定的事件handler QObject與QWidget提供了許多特定的事件handlers,分別對應(yīng)于不同的事件類型。(如paintEvent()對應(yīng)paint事件) 重新實(shí)現(xiàn)QObject::event() event()函數(shù)是所有對象事件的入口,QObject和QWidget中缺省的實(shí)現(xiàn)是簡單地把事件推入特定的事件handlers。 在QObject安裝上事件過濾器 事件過濾器是一個對象,它接收別的對象的事件,在這些事件到達(dá)指定目標(biāo)之間。 在aApp上安裝一個事件過濾器,它會監(jiān)視程序中發(fā)送到所有對象的所有事件 重新實(shí)現(xiàn)QApplication:notify(),Qt的事件循環(huán)與sendEvent()調(diào)用這個函數(shù)來分發(fā)事件,通過重寫它,你可以在別人之前看到事件。 事件列表 Qt4.6的事件列表: QAccessibleEvent QActionEvent QChildEvent QCloseEvent QCustomEvent QDragLeaveEvent QDropEvent QDragMoveEvent QDragEnterEvent QDynamicPropertyChangeEvent QFileOpenEvent QFocusEvent QGestureEvent QGraphicsSceneEvent QGraphicsSceneContextMenuEvent QGraphicsSceneDragDropEvent QGraphicsSceneHelpEvent QGraphicsSceneHoverEvent QGraphicsSceneMouseEvent QGraphicsSceneMoveEvent QGraphicsSceneResizeEvent QGraphicsSceneWheelEvent. QHelpEvent QHideEvent QHoverEvent QIconDragEvent QInputEvent QContextMenuEvent QKeyEvent QMouseEvent QTabletEvent QTouchEvent QWheelEvent QInputMethodEvent QMoveEvent QPaintEvent QResizeEvent QShortcutEvent QShowEvent QStatusTipEvent QTimerEvent QWhatsThisClickedEvent QWindowStateChangeEvent |
|