這裡簡單地介紹VBA中的類別模組,使大家能夠在應用程式中建立並使用簡單的類。
類是對象的“模板”。對象可以是任何事物,而類不會做任何事情,也不會佔用記憶體,只有當類成為對象並使用Set語句和New關鍵字執行個體化為具體對象後,才能做事情並佔用記憶體。執行個體化類為具體對象的文法為:
Dim C As Class1
Set C=New Class1
上述語句建立了一個名為C的對象,該對象的資料類型為定義的類Class1。
在詳細介紹類之前,讓我們先看看VBA的使用者自訂資料類型,即使用Type關鍵字定義的變數。例如,下面的Type變數定義了僱員的資訊:
Type Employee
Name As String
Address As String
Salary As Double
End Type
上面的語句定義了變數Employee,包含元素Name、Address和Salary。接著,您可以聲明一個Employee型的變數,並為其中的每個元素賦值:
Sub test()
Dim Fan As Employee
Fan.Name = “fanjy”
Fan.Address = “YiChang”
Fan.Salary = 1000
End Sub
使用者自訂類型是很有用的,但是有三個主要的局限:
1、在編譯時間必須聲明所有的自訂類型變數。雖然可以使用動態數組來處理多個自訂類型,但必須使用Redim Preserve關鍵詞。並且,不能在運行時添加新的自訂類型變數。
2、不能控制賦給自訂類型中元素的值。例如,在上述代碼中,有可能給Salary元素賦一個負值。
3、自訂類型不做任何事情,只是靜態地儲存資料。
使用者自訂類型被廣泛用於在對Windows API函數調用時,除此之外,使用類別模組是更好的選擇。類克服了使用者自訂類型的局限。
1、使用New關鍵字,可以建立任意數量的類的新執行個體,並且能夠將其儲存在Collection對象中。
2、使用Property Let/Set/Get語句,可以編寫代碼驗證賦給類元素的值,並且可以編寫當值改變時執行的相應代碼。例如,能夠編寫代碼確保Salary的值不為負值。
3、類可以定義方法(使用Sub過程和Function過程),執行某項動作。
下面,讓我們將自訂類型Employee轉換為類。首先,在VBE編輯器中插入一個類別模組,並將其重新命名為CEmployee,1所示。(類別模組由屬性和方法組成,類本身類似於名詞;屬性可以當作形容詞,用來描述類;方法則為動詞,執行操作。)
CEmployee類應該有三個屬性:Name、Address和Salary。在類別模組的聲明部分聲明三個Private變數來儲存這些值,屬性的實際值被儲存在這三個私人變數中。
Private pName As String
Private pAddress As String
Private pSalary As Double
因為這些變數都被聲明為私人的,因此僅能在類內部訪問,在類的外部是不可見的。如何為這些變數賦值呢?這就是Property Let語句要做的工作。每個私人變數都有相應的Property Let語句。
Property Let Name(S As String)
pName = S
End Property
Property Let Address(S As String)
pAddress = S
End Property
Property Let Salary(D As Double)
pSalary = D
End Property
Property Let語句用於給屬性賦值,即將值引入類。在上例中,簡單地將引入的值賦給私人變數。由於Property Let語句中能夠包含代碼,因此能夠編寫用於資料驗證的代碼。例如,改寫Property Let Salary函數中的代碼,使之不允許接受負值:
Property Let Salary(D As Double)
If D > 0 Then
pSalary = D
Else
‘錯誤提示
MsgBox “薪水怎能為負呢?”
End If
End Property
與Property Let函數相對應的是Property Get函數,用於從類中擷取屬性的值。在CEmployee類中,相應的Property Get語句為:
Property Get Name() As String
Name = pName
End Property
Property Get Address() As String
Address = pAddress
End Property
Property Get Salary() As Double
Salary = pSalary
End Property
Let語句和Get語句的資料類型必須相匹配。例如,Let Salary接受Double類型的值作為其參數,這意味著其返回的相應的Get屬性的值必須是Double。如果資料類型不一致,就會導致編譯錯誤。
這些Get語句簡單地將三個屬性向外公開。要建立唯讀屬性,則忽略Property Let語句而僅使用Property Get語句。例如,WithholdingTax屬性是唯讀,在Get語句中的代碼計算合適的值並將其公開,但避免從外部改變該屬性的值:
Property Get WithholdingTax() As Double
WithholdingTax = some_tax_calculation
End Property
該屬性沒有對應的Let語句,因此該屬性唯讀,沒有辦法將值賦給WithholdingTax。
類別模組能夠包含方法,例如CEmployee類有一個用於僱員複核薪水的方法:
Public Sub PrintPaycheck()
‘放置列印複核的實際代碼
End Sub
好了,我們已經完成了CEmployee類的初步定義,1所示。
圖1:CEmployee類
下面,在標準模組的代碼中執行個體化類,並使用其屬性和方法。首先,在VBE編輯器中插入一個模組,聲明一個CEmployee類型的變數。(注意,在複雜的應用程式中,在類別模組中聲明並執行個體化另一個類是完全合法的)
Dim Emp As CEmployee
接下來,執行個體化該類,建立一個可用來工作的實際對象,如下列語句:
Set Emp = New CEmployee
上述語句建立了一個名為Emp的對象,能夠使用CEmployee類中的屬性來引用特定的僱員資訊,例如:
Emp.Name = “fanjy”
Emp.Address = “YiChang”
Emp.Salary = 1000
這三個語句調用在CEmployee類中聲明的Property Let語句來賦值給類中的私人變數。我們能夠使用下列代碼讀取對象的屬性的值:
Debug.Print Emp.Name
Debug.Print Emp.Address
Debug.Print Emp.Salary
上述語句調用類別模組中的Property Get語句並擷取資料。我們也能讀取類中的唯讀屬性WithholdingTax:
Debug.Print Emp.WithholdingTax
由於WithholdingTax屬性沒有相應的Let語句,因此不能給該屬性賦值。如果試圖賦值:
Emp.WithholdingTax = 4000
則會導致:“編譯錯誤:不能給唯讀屬性賦值”。
也能夠調用方法來執行操作:
Emp.PrintPaycheck
在集合中儲存類的多個執行個體
如果到運行時還不知道有多少個僱員,那麼能夠在運行時按需要建立多個Emp對象,每建立一個Emp對象之後將其儲存在集合中。例如:
Dim Coll As New Collection
Dim Ndx As Long
Dim Emp As CEmployee
For Ndx = 1 To NumberOfEmployees
Set Emp = New CEmployee
‘設定Emp對象的屬性
Coll.Add Item:=Emp, Key:=Emp.Name
Next Ndx
上面的For…Next迴圈將建立CEmployee類的NumberOfEmployees個執行個體,具體數量由運行時決定,並將其儲存在名為Coll的集合對象中。之後,能夠使用For Each迴圈從Coll集合中擷取每個僱員資訊或執行操作:
For Each Emp In Coll
Emp.PrintPaycheck
Next Emp
類的Instancing屬性
類的Instancing屬性決定其可見度(或稱作範圍),預設屬性值為1-Private,意味著類僅能在包含該類的工程中建立和訪問。其他工程不能基於該類建立對象。對於絕大多數應用程式來說,Private是足夠了。
Instancing屬性的另一個值是2-PublicNotCreatable,表明其他工程能夠將變數聲明為該類,但是不能使用Set語句建立該類的執行個體。
在多個工程間使用類
如果一個活頁簿需要使用定義在另一個活頁簿中的類,則需要在包含類別模組的活頁簿中編寫代碼匯出類到另一個工程。該類的Instancing屬性必須是2-PublicNotCreatable。
假設Book1.xls活頁簿中包含一個名為Class1的類別模組,Book2.xls需要使用該類。首先,將Book1活頁簿的工程名稱從預設的 “VBAProject”修改為唯一的名稱,例如MyProject。然後,在VBE編輯器中啟用Book2活頁簿的介面,設定對Book1活頁簿的引用,即在VBE中選擇“工具——引用”,然後在列表中選擇“MyProject”。然後,在Book2中,建立如下聲明:
Public C As MyProject.Class1
因為Instancing的屬性值為PublicNotCreatable,所以可以聲明一個Class1類的變數,但不能建立該類的執行個體。因此,需要在Book1中編寫一個函數來建立Class1的新執行個體,並返回該執行個體給Book2。在Book1中,建立下面的過程:
Public Function GetClass1() As Class1
Set GetClass1 = New Class1
End Function
然後,在Book2中設定公開變數C為上述函數的結果,例如:
Set C=MyProject.GetClass1()
現在,C被設定為Class1的新執行個體。
好了,上面只是對類別模組的一些初步介紹,還有一些知識未講述,例如Property Set語句,留待以後在慢慢整理。