大家都知道,和VB不一样,VBA中不能直接创建控件数组。然而可以使用WithEvents来模拟相同的功能。我们需要一个类来处理控件的事件,而每一个控件需要一个类实例。对于不同控件的类实例,我们可以使用一个对象数组或者集合来实现。
这里使用按钮控件做为例子来介绍怎样在窗体和工作表中创建控件数组。
创建类
创建控件数组之前,我们需要一个类来处理控件的事件。
在VBE窗口中,单击菜单“插入”->“类模块”,在属性窗口中将类的名称改为“cCB”。
在类模块中添加下面这一行:
Private WithEvents m_CB As MSForms.CommandButton
这样你就可以从代码栏的顶部左边下拉列表中选择m_CB并选择右边下拉列表中相应的事件。
完整的代码如下:
Private WithEvents m_CB As MSForms.CommandButton ' 初始化,将控件绑定到类 Public Sub Init(ctl As MSForms.CommandButton) Set m_CB = ctl End Sub ' 控件的Click事件 Private Sub m_CB_Click() MsgBox "你点击了:" & m_CB.Caption End Sub ' 注销类 Private Sub Class_Terminate() Set m_CB = Nothing End Sub
窗体中的控件数组
然后创建一个窗体,在窗体中添加两个CommandButton,将这两个按钮控件分别命名为cmd1和cmd2,然后在窗体中的初始化事件中添加代码如下:
Private ctlCB(1 To 2) As cCB ' 以对象数组保存类的实例 Private Sub UserForm_Initialize() Set ctlCB(1) = New cCB ' 将按钮cmd1赋给类的实例 ctlCB(1).Init cmd1 Set ctlCB(2) = New cCB ctlCB(2).Init cmd2 End Sub
这里使用对象数组ctlCB(1 to 2)来保存类实例。每当使用Set语句创建一个类实例,然后使用类的Init方法将按钮控件赋给这个实例。
也可以使用集合来保存这个类的实例。代码如下:
Private colCB As New Collection
Private ctlCB As cCB
‘ 以集合保存类的实例
Private Sub UserForm_Initialize() Set ctlCB = New cCB ' 将按钮cmd1赋给类的实例 ctlCB.Init cmd1 ' 将类的实例加入到集合中 colCB.Add ctlCB Set ctlCB = New cCB ctlCB.Init cmd2 colCB.Add ctlCB End Sub
点击按钮,将弹出对应的消息框。
上面的例子是将手动添加的控件添加到控件数组中。也可以动态创建控件数组。
创建一个新的窗体,然后在窗体的初始化事件中使用Controls集合的Add方法添加CommandButton控件,再将创建好的控件赋给类实例。完整代码如下:
Private ctlCB(1 To 3) As cCB Private Sub UserForm_Initialize() Dim nCtr As MSForms.CommandButton For i = 1 To 3 ' 添加按钮控件 Set nCtr = Me.Controls.Add("Forms.CommandButton.1", "cmdTest" & i) ' 设置按钮控件标题和位置 With nCtr .Caption = "CommandButton_" & i .Move 10, 10 + (i - 1) * 40, 80, 30 End With ' 创建cCB类实例 Set ctlCB(i) = New cCB ' 将控件赋给类实例 ctlCB(i).Init nCtr Next i End Sub
工作表中的控件数组
同样,在工作表中也可以创建控件数组(但和窗体有些不同)。在工作表中分别创建一个Label控件和三个CommandButton控件,如下图:
然后在Label控件的Click事件中添加如下代码:
Dim cmdCtl() As cCB ' 标签控件的Click事件 Private Sub Label1_Click() Dim cmd As OLEObject ' 所有OLE对象 Dim i As Integer ' 重新定义数组 ReDim cmdCtl(1 To Sheet2.OLEObjects.Count) As cCB i = 1 ' 循环所有的OLE对象 For Each cmd In Sheet2.OLEObjects ' 只有CommandButton控件才可以加入到控件数组 If cmd.progID = "Forms.CommandButton.1" Then Set cmdCtl(i) = New cCB cmdCtl(i).Init cmd.Object i = i + 1 End If Next MsgBox "已经将工作表中所有CommandButton控件建成控件数组!", vbInformation End Sub
值得注意的是使用类cCB的Init方法时,不能直接使用cmd变量,因为cmd变量是OLEObject类型。需要使用cmd变量的Object属性返回MSForms.CommandButton变量。
然而在工作表中对于动态创建的控件使用同样的方法创建控件数组时,动态创建的控件并不响应类实例的事件。代码如下:
Dim cmdCtl(1 To 5) As cCB ' 标签控件的Click事件 Private Sub Label1_Click() Dim i As Integer Dim cmd As OLEObject For i = 1 To 5 Set cmd = Sheet3.OLEObjects.Add(ClassType:="Forms.CommandButton.1", _ Left:=Cells(i * 3 + 3, 2).Left, Top:=Cells(i * 3 + 3, 2).Top, Width:=Cells(1, 1).Width * 2, Height:=Cells(1, 1).Height * 1.5) Set cmdCtl(i) = New cCB cmdCtl(i).Init cmd.Object Next i MsgBox "已经成功动态创建控件数组!", vbInformation End Sub
类的实例应该是创建成功了(可以在Init方法中添加一些语句来验证),但就是不响应Click事件,不知道是什么原因,那位知道的同学帮忙解释解释一下,多谢了。