The Event System
?
?
?
The Event System
在Qt中,事件是繼承了虛擬類QEvent的對(duì)象,它代表了程序所發(fā)生的事情或者程序需要知道的一個(gè)外部活動(dòng)的結(jié)果。事件可以被任意?QObject子類的實(shí)例接收和處理,是與widgets密切相關(guān)。本文描述了在一個(gè)典型的程序中事件是如何被傳送和處理的。
How Events are Delivered
當(dāng)發(fā)生一個(gè)事件,Qt通過(guò)構(gòu)造一個(gè)適當(dāng)?shù)?QEvent子類的實(shí)例來(lái)創(chuàng)建事件對(duì)象來(lái)代表它,并通過(guò)調(diào)用vevent()函數(shù)把它傳送到特定的?QObject?實(shí)例。
該函數(shù)本身不處理事件:根據(jù)傳送的事件類型,它為特定的時(shí)間類型調(diào)用一個(gè)事件處理程序,并根據(jù)事件是被接受或忽略發(fā)送一個(gè)響應(yīng)。
一些事件,如QMouseEvent?和?QKeyEvent來(lái)自windows系統(tǒng)。如QTimerEvent,?來(lái)自其他來(lái)源,一些來(lái)自程序本身。
Event Types
大多數(shù)的事件類型有特別的類,尤其是?QResizeEvent,?QPaintEvent,?QMouseEvent,?QKeyEvent,andQCloseEvent.?,它們都繼承了QEvent?和添加了特殊的函數(shù)。如?QResizeEvent?添加了?size()和?oldSize()函數(shù)使得widgets?可以獲得其改變的規(guī)模。
一些類支持多于一種實(shí)際的事件類型。?QMouseEvent?支持鼠標(biāo)按下,雙擊,移動(dòng)和其他相關(guān)操作。
每個(gè)事件都有一個(gè)定義在QEvent::Type的相關(guān)的類型,它可以用作運(yùn)行時(shí)的類型信息以快速確定事件對(duì)象是構(gòu)造自哪個(gè)子類。
由于程序需要多種復(fù)雜的方式的響應(yīng),Qt的事件傳送機(jī)制也是靈活的。QCoreApplication::notify()文檔對(duì)稱進(jìn)行了確切的描述。
Event Handlers
通常事件被傳送的方法是調(diào)用一個(gè)虛函數(shù)。例如,?QPaintEvent?通過(guò)調(diào)用?QWidget::paintEvent().而被傳送。該虛函數(shù)復(fù)雜作出適當(dāng)?shù)捻憫?yīng),通常是重繪widget。如果在你實(shí)現(xiàn)的虛函數(shù)里不能完成所需要的功能,可以調(diào)用基類的實(shí)現(xiàn)。
例如,下面的代碼處理了自定義的checkbox?鼠標(biāo)左鍵按下事件,把其他按鍵按下的事件傳送給基類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); ??? } }如果你想取代基類的函數(shù),你必須自己實(shí)現(xiàn)每件事。然而,如果你只想擴(kuò)展基類的功能,你可以實(shí)現(xiàn)自己想實(shí)現(xiàn)的部分,在任何你不想處理情況,可以調(diào)用基類來(lái)獲得默認(rèn)的處理。
偶爾,可能沒(méi)有特定事件的函數(shù),或者特定事件的函數(shù)功能不充分。最常見的例子包含Tab 按下。通常,?QWidget攔截事件來(lái)移動(dòng)鍵盤焦點(diǎn),但是有的widget需要自己處理Tab 按下事件。
這些對(duì)象可以重新實(shí)現(xiàn)?QObject::event(),,一般的事件處理程序,可以在通常的事件處理之前或之后對(duì)它們的事件進(jìn)行處理,或者完全取代整個(gè)函數(shù)的。一個(gè)既攔截Tab 也有自定義事件的widget?可能包含以下的event()?函數(shù):
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 ??????? returntrue; ??? } ??? } elseif (event->type() == MyCustomEventType) { ??? MyCustomEvent *myEvent =static_cast<MyCustomEvent *>(event); ??? // custom event handling here ??? returntrue; ??? } ? ??? returnQWidget::event(event); }我們注意到對(duì)于沒(méi)有處理的所有情況都調(diào)用了QWidget::event()?,而且返回值表明了事件是否被處理。返回值true阻止了事件被傳遞給其他對(duì)象。
Event Filters
有時(shí)一個(gè)對(duì)象需要檢查并可能攔截被傳送給其他對(duì)象的事件。例如,對(duì)話框一般需要為一下widget過(guò)濾鍵盤按鍵事件。例如,修改返回鍵處理。
QObject::installEventFilter()設(shè)置了eventfilter,,在目標(biāo)對(duì)象的QObject::eventFilter()?函數(shù)里接收事件。事件過(guò)濾器在目標(biāo)對(duì)象之前處理事件,根據(jù)需要允許對(duì)事件進(jìn)行檢查和丟棄。可以用?QObject::removeEventFilter()函數(shù)移除一個(gè)已經(jīng)存在的事件過(guò)濾器。
當(dāng)一個(gè)過(guò)濾器對(duì)象的eventFilter()?實(shí)現(xiàn)被調(diào)用,它可以接受或不接受事件,允許或拒絕更進(jìn)一步的處理事件。如果所有的事件過(guò)濾器允許更進(jìn)一步的處理事件,事件將被發(fā)送給目標(biāo)對(duì)象本身。如果其中某個(gè)事件停止處理,目標(biāo)對(duì)象和后面一些事件過(guò)濾器都接收不到該事件。
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 ??????????? returntrue; ??????? } else ??????????? returnfalse; ??? } ??? returnfalse; }以上代碼演示了另一種攔截Tab按鍵事件并發(fā)送到特定目標(biāo)widget的方法。在這種情況下,事件過(guò)濾器處理了相關(guān)的事件并返回true阻止事件被進(jìn)一步處理。其他的事件則被忽略,事件過(guò)濾器返回false以允許它們被發(fā)送到目標(biāo)widget,通過(guò)任何已經(jīng)安裝的事件過(guò)濾器。
為整個(gè)程序過(guò)濾所有的事件也是可能的,通過(guò)為?QApplication?或QCoreApplication?安裝事件過(guò)濾器。這樣的全局事件過(guò)濾器將會(huì)在特定對(duì)象的過(guò)濾器之前被調(diào)用。這很強(qiáng)大,但是也會(huì)使得整個(gè)程序的事件發(fā)送變慢。
Sending Events
很多程序想創(chuàng)建和發(fā)送自己的事件。你可以用像Qt的事件循環(huán)一樣的方法發(fā)送事件,通過(guò)構(gòu)造合適的事件對(duì)象并用QCoreApplication::sendEvent()和QCoreApplication::postEvent().發(fā)送事件。
sendEvent()立即處理事件。當(dāng)它返回,事件過(guò)濾器和對(duì)象本身已經(jīng)處理了事件。對(duì)于很多事件類型,有一個(gè)isAccepted()函數(shù)用來(lái)獲取最近的處理過(guò)程事件是被接受還是不被接受。
postEvent()把事件傳遞到隊(duì)列等待分發(fā)。下一次主事件循環(huán)運(yùn)行,它進(jìn)行一些優(yōu)化將分發(fā)所有的隊(duì)列中的事件。例如,有一些resize?事件,將被壓縮成一個(gè)事件。同樣的應(yīng)用與paint事件:QWidget::update()調(diào)用?postEvent(),它消除閃爍和增加速度以避免多次重繪。
postEvent()在對(duì)象初始化過(guò)程中也被用到,因?yàn)榘l(fā)出的事件將在對(duì)象的初始化完成之后立即分發(fā)。當(dāng)實(shí)現(xiàn)一個(gè)widget,意識(shí)到事件可能在其生命期的早期被分發(fā)這很重要,在其構(gòu)造函數(shù)中,確保在早期初始化成員變量,在其有機(jī)會(huì)接收到事件之前。
要?jiǎng)?chuàng)建自定義的事件類型,需要定義一個(gè)事件號(hào),必須大于?QEvent::User.
?
?
總結(jié)
以上是生活随笔為你收集整理的The Event System的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CutJS – 用于 HTML5 游戏开
- 下一篇: discuz x2.5插件开发傻瓜图文教