qt事件機制

2021-06-05 20:30:50 字數 4790 閱讀 5630

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動作之外,還可以用物件所帶的事件,或者使用者自定義的事件來實現物件的一些行為處理。現在,我們從頭開始講解。到底什麼是事件呢?事件起源 基於事件如何被產生與分發,可以把事件分為以下三...