coffeegg
qt事件機制
學習了一段時間的qt之後,發現qt的事件機制和其他語言的機制有些不同。qt除了能夠
通過訊號和槽機制來實現一些action動作之外,還可以用物件所帶的事件,或者使用者自
定義的事件來實現物件的一些行為處理。
現在,我們從頭開始講解。
到底什麼是事件呢?
事件起源:基於事件如何被產生與分發,可以把事件分為以下三類。
spontaneous 事件——自發事件
由視窗系統產生,它們被放到系統佇列中,通過事件迴圈逐個處理。
posted 事件
由qt或是應用程式產生,它們被qt組成佇列,再通過事件迴圈處理。
sent 事件
由qt或是應用程式產生,但它們被直接傳送到目標物件。
qt事件迴圈的過程
概來講,事件迴圈如下面所示:
while (!exit_was_called)
while(!spontaneous_event_queue_is_empty)
while(!posted_event_queue_is_empty)
}首先,事件迴圈處理所有的posted事件,直到佇列空。
然後再處理所有的spontaneous事件,最後它處理所有的因為處理spontaneous事件而產
生的posted事件。
send 事件並不在事件迴圈內處理,它們都直接被傳送到了目標物件。
現在看一下實踐中的paint 事件是如何工作的。
當乙個widget第一次可見,或是被遮擋後再次變為可見,
視窗系統產生乙個(spontaneous) paint事件,要求程式重畫widget,事件迴圈最終從事
件佇列中撿選這個事件並把它分發到那個需要重畫的widget。
並不是所有的paint事件都是由視窗系統產生的。當你呼叫qwidget::update()去強行重
畫widget,這個widget會post 乙個paint 事件給自己。這個paint事件被放入佇列,最終
被事件迴圈分發之。
假如你很不耐煩,等不及事件迴圈去重畫乙個widget, 理論上,你應該直接呼叫
paintevent()強制進行立即的重畫。但實際上這不總是可行的,因為paintevent()函式
是protected的(很可能訪問不了)。它也繞開了任何存在的事件過濾器。因為這些原
因,qt提供了乙個機制,直接sending事件而不是posting 。
qwidget::repaint()就使用了這個機制來強制進行立即重畫。
posting 相對於sending的乙個優勢是,它給了qt乙個壓縮(compress)事件的機會。假如
你在乙個widget上連續地呼叫update() 十次,因update()而產生的這十個事件,將會自
動地被合併為乙個單獨的事件,但是qpaintevents事件附帶的區域資訊也合併了。
可壓縮的事件型別包括:paint,move,resize,layout hint,language change。
個物件的posted事件。
人工合成的事件
qt應用程式可以產生他們自己的事件,或是預定義型別,或是自定義型別。這可以通過
這兩個函式需要乙個qobject* 與乙個qevent * 作為引數,假如你呼叫postevent(),你
必須用new 操作符來建立事件物件,qt會它被處理後幫你刪除它。假如你用sendevent
(), 你應該在棧上來建立事件。下面舉兩個例子:
一是posting 事件
(qevent::keypress,key_x,'x',0));
二是sending 事件
qkeyevent event(qevent::keypress, key_x, 'x', 0);
qt應用程式很少直接呼叫postevent()或是sendevnet(),因為大多數事件會在必要時被
qt或是視窗系統自動產生
。在大多數的情況下,當你想傳送乙個事件時,qt已經為了準備好了乙個更高階的函式
來為你服務。(例如
update()與repaint())。
定製事件型別
qt允許你建立自己的事件型別,這在多執行緒的程式中尤其有用。在單執行緒的程式也相當
有用,它可以作為
物件間的一種通訊機制。為什麼你應該用事件而不是其他的標準函式呼叫,或訊號、槽
的主要原因是:事件既可用於同步也可用於非同步(依賴於你是呼叫sendevent()或是
postevents()),函式呼叫或是槽呼叫總是同步的。事件的另外乙個好處是它可以被過濾。
演示如何post乙個定製事件的**片段:
const qevent::type myevent = (qevent::type)1234;
...
事件必須是qcustomevent型別(或子類)的。建構函式的引數是事件的型別,1024以下被
qt保留。其他可被程式使用。為處理定製事件型別,要重新實現customevent()函式:
void mylineedit::customevent(qcustomevent *event)
else }
qcustomevent類有乙個void *的成員,可用於特定的目的。你也可以子類化
qcustomevent,加上別的成員,但是你也需要在customevent()中轉換qcustomeevent到
你特有的型別。
事件處理與過濾
qt中的事件可以在五個不同的層次上被處理
1.重新實現乙個特定的事件handler
qobject與qwidget提供了許多特定的事件handlers,分別對應於不同的事件型別。(如
paintevent()對應paint事件)
2.重新實現qobject::event()
event()函式是所有物件事件的入口,qobject和qwidget中預設的實現是簡單地把事件推
入特定的事件handlers。
3.在qobject安裝上事件過濾器
事件過濾器是乙個物件,它接收別的物件的事件,在這些事件到達指定目標之間。
它會監視程式中傳送到所有物件的所有事件。
qt的事件迴圈與sendevent()呼叫這個函式來分發事件,通過重寫它,你可以在別人之前
看到事件。
特定物件的事件處理
一些事件型別可以被傳遞。這意味著假如目標物件不處理乙個事件,qt會試著尋找另外
的,假如擁有焦點的widget不處理特定鍵,qt會分發相同的事件給父widget,然後是父親
的父親,直到最頂層widget。
那麼何時接收該事件,何時忽略呢?
通過accept( )函式和ignore( )函式。
可被傳遞的事件有乙個accept()函式和乙個ignore()函式,你可以用它們來告訴qt,你
「接收」或是「忽略」這個事件。假如事件handler呼叫accept(),這個事件將不會再被
傳遞。假如事件handler呼叫ignore(),qt會試著查詢另外的事件接收者。像大多數的
開發者一樣,你可能不會被呼叫accept()或是ignore()所煩惱。預設情況下是「接收」
,在qwidget中的預設實現是呼叫ignore(),假如你希望接收事件,你需要做的是重新實
現事件handler,避免呼叫qwidget的實現。假如你想「忽略」事件,只需簡單地傳遞它
到qwidget的實現。下面的**演示了這一點:
void myfancywidget::keypressevent(qkeyevent *event)
else }
在上面的例子裡,假如使用者按了"esc"鍵,我們會呼叫doescape()並且事件被「接收」了
(這是預設的情況),事件不會被傳遞到父widget,假如使用者按了別的鍵,則呼叫
qwidget的預設實現。
void qwidget::keypressevent(qkeyevent *event)
應該感謝ignore(),事件會被傳遞到父widget中去。
討論到目前為至,我們都假設基類是qwidget,然而,同樣的規則也可以應用到別的層次
中,只要用qwidget 代替基類即可。舉例來說:
void myfancylineedit::keypressevent(qkeyevent *event)
else }
由於某些原因,你會在event()中處理事件,而不是在特定的handler中,如
keypressevent(),這個過程會有些不同。event() 會返回乙個布林值,來告訴呼叫者是
否事件被accept或ignore,(true表示accept),從event()中呼叫accept()或是ignore()
是沒有意義的。「accept」標記是event()與特定事件handler之間的一種通訊機制。而
的event()實現是轉換「accept」標記為乙個布林值,如下所示:
bool qwidget::event(qevent *event)
return true; }
到現在為至,我們所說的內容不僅僅適用於key事件,也適用於
mouse,wheel,tablet,context menu等事件。
close事件有點不同,呼叫qcloseevent:ignore()取消了關閉操作,而accept()告訴qt繼
續執行正常的關閉操作。為了避免混亂,最好是在closeevent()的新實現中明確地進行
accept()與ignore()的呼叫:
void mainwindow::closeevent(qcloseevent *event)
else }
來自:
qt 事件機制
什麼是自發事件?哪些型別的事件可以被propagated 或compressed?posting and sending 事件之間有何不同?什麼時候應該呼叫 accept 或是ignore 如果這些問題你還不是很了解,那麼繼續看下去。事件起源 定製事件型別 到現在為至,我們所說的內容不僅僅適用於ke...
QT事件機制
什麼是自發事件?哪些型別的事件可以被propagated 或compressed?posting and sending 事件之間有何不同?什麼時候應該呼叫 accept 或是ignore 如果這些問題你還不是很了解,那麼繼續看下去。事件起源 到現在為至,我們所說的內容不僅僅適用於key事件,也適用...
qt事件機制
學習了一段時間的qt之後,發現qt的事件機制和其他語言的機制有些不同。qt除了能夠通過訊號和槽機制來實現一些action動作之外,還可以用物件所帶的事件,或者使用者自定義的事件來實現物件的一些行為處理。現在,我們從頭開始講解。到底什麼是事件呢?事件起源 基於事件如何被產生與分發,可以把事件分為以下三...