在前面的例子里,我们使用代码插入了不定数量的选项按钮,但是为了激活工作表,还手动插入了一个命令按钮,通过遍历控件的方式,找到要激活的工作表。如果能够不需要命令按钮,只要点击选项按钮就激活工作表,那就更简洁了。
要实现点击选项按钮就激活工作表,显然需要插入的选项按钮具有某个事件,在使用代码插入控件的时候,是可以同时让控件具有事件的:
代码语言:javascript复制Private WithEvents ob As MSForms.OptionButton
在窗体最上面这样写语句的话,就相当于手动插入了一个名称是ob的选项按钮,这样在代码编辑器下拉框里,就能选择ob,然后选择对应的事件。
但是在UserForm_Initialize事件里添加控件,如果使用窗体的全局变量ob的话,ob只能指向最后一个控件,因为它仅仅是一个变量,不会同时指向多个控件。
而窗体的全局变量声明带WithEvents的时候又不能声明为数组控件,所以在窗体里没法插入不定数量,却又带有事件的控件。
这个时候我们就希望如果能使用代码添加事件就好了,可是VBA没有设置这样的接口。
VB.NET这样的语言是有AddHandler 这样的方法去使用代码添加事件的。
那么在VBA里还有没有办法呢?
其实这个功能的实现只要有一种对象,能够让我们添加控件,同时这个对象内部又能让我们编辑控件事件的代码。这种对象和以前说到过的类是不是很像?类就是一种对象,而且这种对象就是可以让使用者来自定义的。
是的,只要结合类,就能够完成这么一个功能,新建一个类模块,命名为COB,编辑代码:
代码语言:javascript复制'定义私有变量OptionButton
Private WithEvents ob As MSForms.OptionButton
'设置属性OptionButton
Property Set OptionButton(v As MSForms.OptionButton)
Set ob = v
End Property
'OptionButton的Change事件
Private Sub ob_Change()
If ob.Value Then
Worksheets(ob.Caption).Activate
End If
End Sub
这样,这个类就具有了MSForms.OptionButton的属性,而且内部也实现了Change事件,只要控件的Value改变了,就会运行代码。
说明(重要):
这里使用了Private来声明私有变量,故意不使用Public的目的是:
如果使用Public,是可以省略Property属性的,看起来是更方便了。但是作为写程序,一定要非常的严谨,因为这个属性在这里只需要设置,而不希望让外部读取,如果使用Public,外部是可以设置、也可以读取。
Public这种处理方式可能会造成一些问题,比如:设计了一个类,有一个属性Num,这个属性设计类的时候是希望它不能被设置小于10的数字,如果使用Public声明变量的形式,那么这个属性将被外部不可控制的设置任意值。
而如果使用Property属性的方法,在Property Let里,就可以去检测传递的参数是否符合要求,不符合要求的情况下就提前退出Property,就能够避免设置非法的值。
在窗体中编辑代码:
代码语言:javascript复制Option Explicit
'声明COB数组,记录COB对象
Private cobs() As COB
Private Sub UserForm_Initialize()
'定义MSForms.OptionButton变量
Dim ob As MSForms.OptionButton
Dim i As Long
Dim itop As Integer
itop = 10
ReDim cobs(Worksheets.Count - 1) As COB
For i = 1 To Worksheets.Count
'添加选项按钮
Set ob = Me.Controls.Add("Forms.OptionButton.1")
'以工作表名称设置选项按钮内容
ob.Caption = Worksheets(i).Name
'设置选项按钮的位置
ob.Left = 5
ob.Top = itop
'记录下一个选项按钮应该出现的位置
itop = itop ob.Height 10
'实例化COB
Set cobs(i - 1) = New COB
'设置COB的OptionButton属性
Set cobs(i - 1).OptionButton = ob
Next
'设置窗体的高度,防止工作表太多看不到
Me.Height = itop 20
End Sub
这样就能够实现直接点击选项按钮,激活对应的工作表。