VBA中自定義類和事件的(偽)注冊


想了解一下VBA中自定義類和事件,以及注冊事件處理程序的方法。

折騰了大半天,覺得這樣的方式實在稱不上“注冊”,所以加一個“偽”字。純粹是瞎試,原理也還沒有摸透。先留着,有時間再接着摸。

做以下嘗試:

1、建一個自定義類(類模塊),類名:Qiqiu

    該類提供一個Daqi的方法,每執行一次,x(記錄氣球的體積)的值+i,如果x的值大於max,則觸發自定義的Change事件。

    為節省細節不使用屬性過程,變量直接用public

 1 Public Event Change(q As qiqiu)   'Event關鍵字聲明事件,事件參數是Qiqiu類型。 
'推模式還是拉模式?一直感覺有參數的都該是推模式,傻傻分不清楚啊。 2 Public x As Integer '記錄實際體積 3 Public max As Integer '記錄最大體積 4 Function Daqi(i As Integer) '模擬給Qiqiu打氣的情形 5 x = x + i 6 If x > max Then 7 RaiseEvent Change(Me) 'RaiseEvent關鍵字觸發事件。在事件觸發時,把自已的實例引用傳給訂閱者。 8 x = 0 9 End If 10 End Function

2、建三個簡單窗體MainFrm,UserFrm1,UserFrm2

    MainFrm啟動后,點擊“彈出窗體按鈕”,UserFrm1和UserFrm2顯示出來

   

3、UserFrm1、UserFrm2需要關聯Qiqiu的Change事件(觀察氣球狀態的變化對事件做出響應),需要做一些准備

    下面是UserFrm1中的代碼(為簡化案例,UserFrm2的代碼和UserFrm1完全相同,實際上可以完全是不同的響應)

    注意第一行的WithEvents關鍵字的變量聲明,后面需要使用這個變量將方法(事件處理程序)關聯到事件。

1 Public WithEvents qiu As Qiqiu          '關聯Qiqiu的事件的關鍵,維護一個Qiqiu的引用,既然有引用,本案的Change事件的參數就顯得很多余。
2 
3 Private Sub qiu_Change(q As Qiqiu)      '事件的響應程序
4 Me.TextBox1 = "氣球爆炸了,爆炸時體積是:" + CStr(q.x) 5 End Sub

4、MainFrm主窗體代碼:

 1 Public q As Qiqiu 
 3 Private Sub UserForm_Initialize()
 4     Set q = New Qiqiu                      '窗體初始化,初始化Qiqiu類的實例
 5     q.max = 10                             '將q的最大體積設定為10
 6 End Sub
 8 
 9 Private Sub btn_Click()              '點擊按鈕“彈出窗體”執行的代碼,實例化UserFrm1和UserFrm2並顯示 
11 Dim f1 As UserFrm1, f2 As UserFrm2
13   Set f1 = New UserFrm1
14   Set f2 = New UserFrm2
16   Set f1.qiu = q        '第3中的WithEvents關鍵字聲名的變量在此處使用
17   Set f2.qiu = q        '使f1.qiu,f2.qiu分別指向Qiqiu類的實例q(即:注冊)
19     f1.Show False
20     f2.Show False
22 End Sub
23 
24 Private Sub btndq_Click()          '點擊按鈕“打氣”執行的代碼   
26      q.daqi (5)                    '調用q的打氣方法給Qiqiu打氣,每次打入氣體體積為5。當q.x大於q.max時觸發事件  
28 End Sub

 5、程序執行效果:(雖然實現了效果,但理解上感覺模模糊糊)

      打氣三次時觸發事件(此時氣球的體積是15,超過了氣球的max體積10),事件關聯的處理程序提示,氣球爆炸,並獲取爆炸時的體積

    

6、小結:

     VBA中,類的事件可能是很封閉的。不像C#事件開放了注冊和移除的接口,只要方法簽名相同,就可以很方便的指向事件的響應方法,根本不需要在訂閱者類的內部再聲明和發布者直接相關東西(變量引用),減小耦合度。

     其實摸索了VBA的對象瀏覽器后,也可以找到類中事件的冰山一角,可以看到它的簽名。比如Worksheet的Change事件。

    

7、補充一點轉來的總結(我自己按想法修改了一些用詞):

    主題對象(被觀察者、事件發布者)對客戶端(觀察者、訂閱者)一無所知

  1. 觀察者引用一個主題對象,對這個觀察者,它可將引用放置在 WithEvents 變量中來處理那些主題對象。發布者沒有訂閱者的信息。它向未知數目的聽眾進行廣播, 劇院中可能一個觀眾都沒有。
  2. 主題對象不會控制接收事件的觀察者的次序。(好像這點和C#有很大不同,C#事件注冊的順序可以決定事件的執行順序)
  3. 當對象引發事件時,其所有訂閱者都在引發事件的對象再次獲得控制之前處理該事件。
  4. 如果事件包含 ByRef 參數,則該參數可被任何處理事件的客戶程序改變。只有最后的客戶端進行的改變才對引發事件的對象可見,因為(如上所述),直到所有客戶端都處理該事件之前,引發事件的對象不會再度獲得控制。

    為了將某個事件添加到一個類中,然后使用該事件,可以這樣做:

  1. 在定義類的類模塊聲明部分,用 Event 語句來聲明事件—該事件帶有希望它帶有的任何參數。事件總是 Public。 注意 事件不能有命名的參數、Optional可選的參數、或 ParamArray可變參數。事件沒有返回值。
  2. 在類模塊代碼中的合適地方,用 RaiseEvent 語句來引發事件,並提供所需要的參數。
  3. 在將要處理事件的模塊聲明部分,使用 WithEvents 關鍵字,添加該類類型的變量。它必須是一個模塊級的變量。
  4. 在代碼窗口左邊的下拉菜單上,選擇聲明為 WithEvents 的變量。
  5. 在代碼窗口右邊的下拉菜單上,選擇希望處理的事件。(可以為類聲明多個事件。)
  6. 使用所提供的參數,將代碼添加到事件過程中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM