为了创建此示例,打开一个新工程并插入两个类模块。在窗体上画出五个命令按钮、一个列表框、两个文本框,以及两个标签,如图 9.13 所示。
图 9.13 Employees 集合示例
下表列出了该示例所需设置的属性值。
对象 | 属性 | 设置值 |
类模块 | Name | Employee |
类模块 | Name | SmallBusiness |
窗体 | Caption | 雇员集合 |
第一个命令按钮 | Caption Name |
添加 cmdAddEmployee |
第二个命令按钮 | Caption Name |
删除 cmdDeleteEmployee |
第三个命令按钮 | Caption Name |
刷新表 cmdListEmployees |
第四个命令按钮 | Caption Name |
有问题 cmdTrouble |
第五个命令按钮 | Caption Name |
关闭 cmdClose |
第一个标签控件 | Caption | Name |
第二个标签控件 | Caption | Salary |
第一个文本框 | Name Text |
txtName (blank) |
第二个文本框 | Name Text |
txtSalary (blank) |
列表框 | Name | lstEmployees |
在 Employee 类模块中,将下面的声明和属性过程添加进去:
Option Explicit 'Employee
类的属性。Public Name As String
Public Salary As Long
'
只写一次ID
属性的私有数据。Private mstrID As String
Property Get ID() As String
ID = mstrID
End Property
'
首次设置ID
属性时,静态的Boolean
变量也要设置。'
后续的调用什么也不做。'
(若不是这样,产生一个错误会更好。)
Property Let ID(strNew As String)
Static blnAlreadySet As Boolean
If Not blnAlreadySet Then
blnAlreadySet = True
mstrID = strNew
End If
End Property
ID 属性是从集合中检索或者删除 Employee 对象的键,因此必须对它进行一次性设置并不再更改。这是用 Static Boolean 变量来完成的,该变量在首次设置 ID 属性的时候被设置为 True。该属性总是可读的,因为有一个 Property Get。
在 SmallBusiness 类模块中,将下面的声明添加进去。当代码中引用 Employees
变量时,将创建集合对象。
Option Explicit
Public Employees As New Collection
所有的剩余代码都在窗体模块中。在声明部分添加下面的声明。
Option Explicit
Public sbMain As New SmallBusiness
cmdEmployeeAdd_Click 事件中的代码,将一个成员添加到集合。
Private Sub cmdEmployeeAdd_Click() Dim empNew As New Employee Static intEmpNum As Integer '
用With
语句,使代码更快,也更简洁'
(.ID
对应empNew.ID)
。With empNew
'
为新的雇员产生一个唯一的ID
。intEmpNum = intEmpNum + 1
.ID = "E" & Format$(intEmpNum, "00000")
.Name = txtName.Text
.Salary = CDbl(txtSalary.Text)
'
将Employee
对象引用添加到集合中,'
用ID
属性作为键。sbMain.Employees.Add empNew, .ID
End With
txtName.Text = ""
txtSalary.Text = ""
'
单击“刷新表”按钮。cmdListEmployees.Value = True
End Sub
在 cmdListEmployees_Click 事件过程中的代码,用一个 For Each ... Next 语句将所有的雇员信息添加到 Listbox 控件中。
Private Sub cmdListEmployees_Click()
Dim emp As Employee
lstEmployees.Clear
For Each emp In sbMain.Employees
lstEmployees.AddItem emp.ID & ", " & emp.Name _
& ", " & emp.Salary
Next
End Sub
cmdEmployeeDelete_Click 事件用 Collection 对象的 Remove 方法,删除当前 ListBox 控件中选定的集合对象。
Private Sub cmdEmployeeDelete_Click() '
检查一下,以确保有被选中的雇员。If lstEmployees.ListIndex > -1 Then
'
前六个字符是ID
。sbMain.Employees.Remove _
Left(lstEmployees.Text, 6)
End If
'
单击“刷新表”按钮。cmdListEmployees.Value = True
End Sub
将下面的代码添加给“有问题”按钮。
Private Sub cmdTrouble_Click() '
说些什么!?sbMain.Employees.Add Me
End Sub
cmdClose_Click 事件关闭该应用程序。当关闭使用对象的工程时,卸载所有窗体,确保类模块中的所有 Terminate 事件过程都将得到执行。相反,使用 End 语句终止程序显得生硬,不会执行 Terminate 事件。
Private Sub cmdClose_Click()
Unload Me
End Sub
在示例中,为了添加雇员,可以运行应用程序,在两个文本框中输入值,然后选取“添加”按钮。添加几个雇员,然后用删除和列表按钮来作一下实验。
这种简单的实现方法不是很强健。因为 Employees 属性仅仅是一个公有的 Collection 对象,可能无意中在程序中的任何地方访问它。而且,Collection 对象的 Add 方法不作任何类型检查。例如,在“有问题”按钮的 Click 事件中的代码,会轻率地将对窗体的对象引用插入到雇员集合中。
单击“有问题”按钮,会注意到未出现任何错误。现在,单击“刷新表”按钮。当 For Each ... Next 循环遇到意外的对象类型时,它将导致类型为 13 的错误发生,即“类型不匹配”。
这是用公用的 Collection 对象建立对象模型时,可能会碰到的错误的一个示例。可以从工程的任何地方添加对象,而且对于它们是否将被正确地初始化,没有任何保证。如果程序员复制代码以添加雇员,而且原始代码后来又有所改动,那么要找到产生的错误非常困难。
详细信息 本主题中开始探讨的这个示例,在下面的“私有集合示例:树枝盖的房子”中将继续讨论。