VBA中使用类和事件的注册

Posted 业余爱好

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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. 使用所提供的参数,将代码添加到事件过程中。

以上是关于VBA中使用类和事件的注册的主要内容,如果未能解决你的问题,请参考以下文章

插入代码时,打开事件中的 Excel 2010 vba EnableEvent 不起作用

关于片段生命周期

EXCEL VBA 事件的问题。

分配给每个事件的类似 VBA 代码的历史功能

如何使用 VBA 将事件添加到运行时在 Excel 中创建的控件

VBA:在预处理时访问注册表