wxWidget的事件機制

2021-05-28 09:46:36 字數 2615 閱讀 5208

wxwidget 的事件機制

wxwidget 通過在編譯期生成靜態的事件表來實現事件類的事件處理。所有想要使用事件處理機制的地方都需要繼承 wxevthandler 類(直接或間接)。

由於 window 控制項需要處理自身的 ui 時間,故 wxwidget 將實現為 exevthandler 的基類,這就意味著所有的 wxwidget 的控制項均是事件類,可以直接定義事件表。

a) 定義事件表的基本步驟:

1) 定義乙個直接或間接繼承自 wxevthandler 的類;

2) 定義所需的事件處理函式,函式格式: void func(wx***event& evt);

3) 在類的定義中使用 declare_event_table() 宣告事件表;

4) 在 cpp 檔案中使用 begin_event_table( sourcepanel, wxpanel ) 和 end_event_table() 定義事件表。

5) 使用相應的事件巨集在事件表中建立事件與處理函式的對映。

b) 視窗的事件查詢流程:

當前視窗事件類 ->1 級繼承的事件類 ->2 級繼承事件類 ->….-> 父視窗事件類 …

上述的事件查詢過程是建立在事件沒有被處理的前提下。如果某個事件類處理了該事件,並沒有呼叫 skip() ,那麼該事件將被認為已經處理完畢,查詢終止。

熟悉視窗的事件查詢流程,對於有效處理事件極為關鍵。

使用者可以通過提前截獲某事件,從而阻斷後續的處理流程;使用者也可以提前截獲事件,增加額外的事件處理邏輯 ( 需呼叫 skip) 。

c) wxwindow 類的內部事件處理機制:

每個視窗類的內部均維護乙個事件表棧,在事件傳遞給某個視窗類時,視窗類將事件逐一匹配事件表棧中事件表,也就是說最後放入的事件表將最先被匹配。使用者可以通過 wxwindow::pushevnethandler 來壓入事件表,通過 popeventhandler 彈出事件表。一定要確保事件表中的事件處理物件的生存期大於視窗物件的生存期,除非 popeventhandler ,並刪除了該事件物件。記住:視窗本身也是乙個事件處理物件,並作為第乙個 eventhandler 被壓入事件表棧。

wxwindow 的處理機制決定了使用者可以通過,改變事件表棧的順序臨時或永久的改變圖形介面的行為。使用者可以通過自定義的 wxevthandler 類,截獲視窗事件,從而實現增加處理邏輯或過濾視窗事件的行為。

d) 下述事件不會傳給事件源控制項的父視窗,即當前視窗有效:

wxactivate, wxcloseevent, wxeraseevent, wxfocusevent, wxkeyevent, wxidleevent, wxinitdialogevent, wxjoystickevent, wxmenuevent, wxmouseevent, wxmoveevent, wxpaintevent, wxquerylayoutinfoevent, wxsizeevent, wxscrollwinevent, wxsyscolourchangedevent 。

這麼設計是因為這些控制項僅對當前視窗有意義。當然這是 wxwidget 設計者的想法。在實際程式設計中,可能需要截獲 wxmouseevent , wxkeyevent 等事件,並增加其他的處理邏輯,比如過濾相應的 key 事件等。有三種常見辦法:

1) 過載視窗類,在新類中截獲事件;

2) 過載 wxevthandler ,在新 handler 中截獲事件;見 wxwindow 類事件處理機制。

3) 使用動態的事件處理函式 connect 。不常用,不介紹。

問題:如何在父視窗中截獲子視窗的內部事件,如 wxmouseevent ?

這個問題不難。根據上面的分析, 1) 過載視窗類並不現實,因為 wxmouseevent 不會傳給父視窗。 3) 動態事件處理機制可以實現,但是需要過載視窗類,重新 connect 事件與事件處理函式。 2) 過載 wxevthandler ,實現所需邏輯,並將該物件壓入子視窗,從而達到事先截獲子視窗事件的目的。個人感覺 2) 最為方便。

那麼有個問題:可否直接將父視窗 push 給子視窗呢?答案是:不行,雖然所有視窗均是 wxevthandler 物件。為什麼呢?因為所有的 wxwindow 物件對事件的處理都是極其複雜的,使用父視窗去攔截子視窗事件,會引起混亂,因為所有子視窗的事件都會首先傳給父視窗。實踐證實:將父視窗 push 給子視窗會引發異常。

e) 視窗識別符號

所有的 wxcommandevent 均可以在多個視窗之間傳遞,如何實現特定視窗處理特定事件呢? wxwidget 使用視窗識別符號來標識視窗,從而在事件系統中實現定位特定視窗的作用。視窗識別符號並不要求系統唯一,僅僅需要在特定的上下文中唯一即可。

視窗識別符號僅僅是要使事件處理機制能夠定位特定視窗,從而實現事件與視窗的對映。這意味著並不是所有的事件都關心視窗 id ,尤其是那些不傳遞給父視窗的事件。

假設 wxwidget 的事件處理機制是完備的,那麼通過事件巨集,即可判斷該事件是否會傳遞給父視窗:需要對映視窗 id 的事件巨集意味著該事件會傳遞給父視窗,反之,不然。

f) 事件物件的常用介面

1) skip()   是否繼續傳遞該事件 ( 繼續處理 )

2) 傳遞引數:如 int , long , string , void* 等變數

3) wxnotifyevent::veto()  使本次事件失效,相當於未發生

C 的事件機制

c 的事件機制是基於委託實現的。實現乙個事件,要先定義乙個委託型別 class1 然後我們可以使用 和 註冊 移除事件 class1.event1 new mydelegate new myeventargs 在class中引發事件時最好這樣 class1 如果不想宣告自己的委託型別的話,可以使用s...

Remoting的事件機制

概念就不說了,具體參見msdn相關章節 我們為主執行緒方法新增事件,能不斷的引發事件來匯報處理的進度 public class myeventargs public myeventargs int rate public class myobject console.writeline 主線程方法結...

redis的事件機制

相當清晰 每個cs程式尤其是高併發的網路服務端程式都有自己的網路非同步事件處理庫,redis不例外。我們從redis啟動的main函式開始,從使用者發出連線鍵入命令開始遍歷網路事件庫所涉及的函式,unix套介面相關函式不表。首先對幾個最常用物件進行解釋。redis啟動的時候 init server ...