Excel物件模型簡介
在介紹Excel物件模型之前,讓我們先來看一個簡單的例子。大多數工廠都是按這樣的結構進行設定的:最上層為工廠總部,第二層次分為各個車間,在車間下面又分各班組。就這樣組織在一起,形成了一個工廠體系。Excel物件模型與此相似,看起來複雜但實質上很簡單清晰。
提示 任何看起來複雜的東西其實都是由一些簡單的部分組成的,或者其實它本身就比較簡單。
Excel的物件模型是通過層次結構很有邏輯地組織在一起的,一個物件可以是其它物件的容器,可以包含其它的物件,而這些物件又包含其它的物件。位於頂層的是Application物件,也就是Excel應用程式本身,它包含Excel中的其它的物件,如Workbook物件;一個Workbook物件包含其它一些物件,如Worksheet物件;而一個Worksheet物件又可以包含其它物件,如Range物件,等等。這就是Excel的物件模型。
例如,Range物件在Excel物件模型中的位置為:
Application物件
Workbook物件
Worksheet物件
Range物件
知道了某物件在物件模型層次結構中的位置,就可以用VBA程式碼方便地引用該物件,從而對該物件進行操作,並以特定的方式組織這些物件,使Excel能根據您的需要自動化地完成工作任務。因此,要熟練掌握Excel VBA程式設計,必須理解Excel的物件模型。
在VBA幫助系統中有Excel物件模型的層次結構圖,您可以參閱。
集合
集合是物件,是一組屬於同一型別的物件或相關的物件的集,作為它們的容器。例如,Workbooks物件是當前開啟的所有Workbook物件的集合,Worksheets是包含在某個Workbook物件中的所有Worksheet物件的集合。
物件的引用
■ 使用VBA可以處理某個物件的整個集合,或者某集合中的一個單獨的物件。
語法:集合(“物件名”) 或 集合(物件索引號)
說明:引用集合中的某個物件,即物件名或物件索引號所代表的物件
例如,Worksheets(“Sheet1”)引用集合Worksheets中的工作表Sheet1;若Sheet1是集合中的第一個工作表物件,還可以寫為Worksheets(1)。
特別地,”Sheets”集合由工作簿中的所有工作表(包括圖表工作表)組成。若要引用工作簿中的第一個工作表,可採用語句Sheets(1)表示。
■ 通過點運算引用某物件的成員
我們可以用句點連線物件名來限定是對某個物件成員的引用,同時也指定了該物件成員在物件層次結構中的位置。
語法:<物件名>.<物件名>. …
說明:後一物件是前一物件的成員,限定了對前一物件所包含的物件成員的引用
例如,Application.Workbooks(“Book1.xls”).Worksheets(“Sheet1”).Range(“A1”) 表明是對工作簿Book1上的工作表Sheet1中單元格A1的引用,其中Application代表Excel應用程式本身,可省略。特別地,若Book1是當前活動工作簿,則上述語句可簡寫為 Worksheets(“Sheet1”).Range(“A1”) ;若Sheet1是當前活動工作表,則又可簡寫為 Range(“A1”) 。因此,若在引用中省略了工作簿物件,則表明是使用當前活動工作簿;若再省略了工作表物件,則表明是使用當前活動工作表。
設定物件變數
物件變數是代表一個完整物件的變數,如工作表或單元格區域。用Dim或Public語句來宣告物件變數。
語法:Dim(或Public) <變數名> AS <物件名>
說明:將<變數名>宣告為一個<物件名>物件。
一般可將物件名直接設為Object,即任意物件。但如果您知道變數將作用到的物件的話,最好將其設定為具體的物件。
例如,語句:Dim DataArea As Range,將變數DataArea宣告為一個Range物件。
在將變數宣告為一個物件變數後,用Set語句將某物件賦值給該變數。
語法:Dim(或Public) <變數名> AS <物件名>
Set <變數名>=<某物件>
說明:將<變數名>宣告為一個<物件名>物件,再將某物件賦值給該變數。
現在,讓我們來看看下面兩個簡單的例子,其作用是在工作簿Book1的工作表Sheet1中的A1至B10單元格區域輸入數值666,並將它們格式化為粗體和斜體。
Sub 沒有設定物件變數()
WorkBooks(“Book1.xls”).Worksheets(“Sheet1”).Range(“A1:B10”).Value=666
WorkBooks(“Book1.xls”).Worksheets(“Sheet1”).Range(“A1:B10”).Font.Bold=True
WorkBooks(“Book1.xls”).Worksheets(“Sheet1”).Range(“A1:B10”).Font.Italic=True
End Sub
***************************************
Sub 設定了物件變數()
Dim DataArea As Range
Set DataArea = WorkBooks(“Book1.xls”).Worksheets(“Sheet1”).Range(“A1:B10”)
DataArea.Value=666
DataArea.Font.Bold=True
DataArea.Font.Italic=True
End Sub
比較這兩個程式,其功能相同,但可以看出,當我們設定了物件變數後,不僅可減少手工輸入重複的程式碼,而且使得程式碼得到了明顯的簡化。
此外,對於稍複雜一點的程式,設定物件變數後,由於減少了要處理的點運算子的數目,因此可使得程式碼的執行速度更快。
當設定的變數執行完畢後,應將該變數釋放,以節省記憶體空間。其語法為:
語法:Set <變數名>=Nothing
物件的方法和屬性
在引用了物件或者設定了物件變數後,我們就可以對該物件進行所需要的操作或設定了。這就需要使用物件的方法和屬性。
■ 物件的方法
物件都有方法,一個方法就是在物件上執行的某個動作。為物件指定方法時,應將物件和方法組合在一起,中間用句點分隔。
語法:<物件>.<方法> <引數>
說明:為某物件指定方法。若該方法帶有引數或需要為帶引數的方法指定引數時,則指定引數以執行進一步的動作;若該引數返回值,則應在引數兩邊加上括號。
例如,語句Worksheets(“Sheet1”).Range(“A1:B2”).ClearContents,執行Range物件的ClearContents方法,清除A1至B2單元格區域的內容,但保留該區域的格式設定;而語句 Worksheets(“Sheet1”).Range(“A1:B2”).Clear,執行Range物件的Clear方法,清除A1至B2單元格區域的內容,並刪除所有的格式。
■ 物件的屬性
物件都有屬性,用來描述或設定物件的特徵。可以使用VBA來設定物件的屬性,也可以對一個物件的某些屬性進行修改,從而定義該物件,還可以引用某物件的屬性值。使用屬性時,應將物件和屬性組合在一起,中間用句點分隔。
語法:<物件>.<屬性> <引數>
說明:設定或引用某物件的屬性。若該屬性帶有引數或需要為帶引數的屬性指定引數時,則指定引數以進一步描述該物件;若該引數返回值,則應在引數兩邊加上括號。
語法:<變數>=<物件>.<屬性>
說明:將某物件的屬性值賦值給一個變數,以便於在程式中使用。
例如,Range物件有一個Value屬性,可以用VBA程式碼引用該物件的屬性值,也可以修改該屬性,如下面的語句:
Worksheets(“Sheet1”).Range(“A1”).Value,該語句引用當前工作簿上工作表Sheet1中單元格A1的值。
Worksheets(“Sheet1”).Range(“A1”).Value=666,該語句將當前工作簿上工作表Sheet1中單元格A1的值改為666。
Dim Var As Variant
Var=MyForm.Caption
上面兩句將MyForm物件的Caption屬性賦值給變數Var。
提示 (1) 大多數物件都有一個預設的屬性,如Range物件的預設屬性是Value屬性。對於預設的屬性可省略屬性代號的書寫,即Range(“A1”).Value與Range(“A1”)所表達的意思一樣。即便如此,仍建議還是要將屬性代號寫全,以提高程式的可讀性。
(2) 訪問一個物件不存在的屬性時,會返回一個錯誤。
■ 方法和屬性的引數
大多數方法都帶有引數,從而能進一步定義動作。例如,Range物件的Copy方法帶有一個引數,用來定義將單元格區域的內容複製到什麼地方。語句
Worksheets(“sheet1”).Range(“A1”).Copy Worksheets(“sheet2”).Range(“A1”)表示將當前工作簿上工作表Sheet1中單元格A1的內容複製到當前工作簿上工作表Sheet2中單元格A1中。
在一些情況下,方法帶有一個或多個可選的引數。如果方法使用了可選的引數,則應該為這些引數插入空白佔位符。例如,工作簿物件的Protect方法有三個引數,即密碼、結構和視窗,對應於“保護工作簿”對話方塊中的相應選項,其語法為:
語法:<工作簿物件>.Protect (Password,Structure,Windows)
說明:保護工作簿使其不至被修改。三個引數均為可選引數,其中Password指定密碼,若省略該引數,則不用密碼就可以取消對該工作簿保護;Structure引數指定是否保護工作簿結構;Windows引數指定是否保護工作簿視窗。
若要保護工作簿“Book1.xls”,可使用語句:
Workbooks(“Book1.xls”).Protect “xYzRq”,True,False
其中,第一個引數指定了保戶該工作簿的密碼,注意密碼區分大小寫;第二個引數為True表明工作簿結構受到保護;第三個引數為False表明不保護視窗。
若不想指定密碼,可使用語句:
Workbooks(“Book1.xls”).Protect ,True,False
該語句省略了第一個引數,表明不指定保護密碼,但必須在該引數出現的位置用一個逗號佔位符代表該引數。
讓我們再看看下面的語句:
Workbooks(“Book1.xls”).Protect Structure:=True,Windows:=False
該語句的功能與上面語句相同,即對工作簿不指定保護密碼,要保護工作簿結構,但不保護它的視窗。區別在於,該語句使用了命名的引數,對省略的引數沒有使用空白佔位符。因此,當某方法帶有多個可選的引數,但在VBA語句中只需使用其中的一些引數時,使用命名的引數,可以不必對省略的引數使用空白佔位符,且使程式碼更具可讀性。注意,在引數名和引數值之間用“:=”連線。
還有一種情況,物件的屬性(和方法)可能返回一個值。對於返回一個值的屬性(和方法)來說,必須用括號將引數括起來。例如,Range物件的Address屬性返回一個值即單元格區域的引用地址,該屬性帶有5個可選的引數。若寫成下面的語句:
Range(“A1”).Address False,由於引數缺少括號,所以會出現錯誤。正確的表達如下:
Range(“A1”).Address(False)
或使用命名的引數Range(“A1”).Address(rowAbsolute:=False)。
■ 集合的方法和屬性
集合物件一般有特殊的屬性和可以用來管理該物件的方法。通常,集合物件有Add方法、Item方法和Remove方法,總有一個Count屬性用來返回集合中的物件個數。
物件小結
下面,對前面所描述的知識作一個簡短的小結。
■ 在Excel中,Application物件代表Excel應用程式本身,其它的物件都從它開始。每個物件都有自已的方法和屬性,並且某些物件的一些方法和屬性是相同的。
■ 在通常情況下,我們認為先需要選擇物件,然後再對所選物件進行處理,巨集錄製器就是這樣的。事實上,在不進行選擇的情況下,直接在物件上執行動作將會更有效且執行快速。
■ 在大多數情況下,需要通過引用物件所在的集合間接地引用某個物件。例如,Workbooks(“Book1.xls”)在工作簿集合中引用名為Book1的Workbook物件。
■ 屬性可以返回對另一個物件的引用,一定要認識到這一點。例如,語句Range(“A1”).Font.Bold=True中,Font屬性返回Range物件中所包含的一個Font物件。
■ 要引用一個物件,可以使用很多不同的方法。您可以根據程式執行所處的實際環境,以方便和易於理解為原則,確定具體使用何種方法。
物件的事件
Excel物件模型帶有面向物件程式設計的特點,但VBA也致力於事件驅動的程式設計模型。當某物件上的一個事件發生時,相應的程式執行。事件可以由應用程式觸發,也可以是在進行某個操作時產生。
例如,在VBE編輯器的工程視窗中,雙擊Microsoft Excel物件模型下面的ThisWorkbook物件,在右側程式碼視窗頂部有兩個下拉列表框,其左側為物件列表,右側為過程列表。選擇左側物件列表中的物件,右側列表中則相應列出響應該物件的事件。
可以利用物件的事件定製應用程式。例如,當開啟工作簿時顯示歡迎視窗,這需要選擇ThisWorkbook物件的Open事件,在Private Sub Workbook_Open()過程中呼叫顯示歡迎視窗的程式。
處理物件和集合的兩個重要語句
您如果要想使用VBA有效地處理Excel物件模型,則需要經常使用With…End With語句和For Each…Next語句,它們可以簡化對物件和集合的處理。
■ With … End With語句
With … End With語句可以對某個物件執行一系列的操作,而不必重複指出該物件的名稱。其語法為:
With <物件>
[語句程式碼]
End With
其中,<物件>表示With語句要執行操作的具體物件,[語句程式碼]為對某物件執行操作的一條或多條語句,前面以點運算子開頭。
考慮下面的程式,該程式對當前工作簿中的工作表Sheet1上的單元格區域A1:B10進行操作,設定該區域的字型樣式、字型大小、下劃線、以及字型顏色等屬性。
Sub 設定格式1()
Worksheets(“Sheet1”).Range("A1:B10").Font.Name = "Arial"
Worksheets(“Sheet1”).Range("A1:B10").Font.FontStyle = "Bold Italic"
Worksheets(“Sheet1”).Range("A1:B10").Font.Size = 10
Worksheets(“Sheet1”).Range("A1:B10").Font.Underline = xlUnderlineStyleSingle
Worksheets(“Sheet1”).Range("A1:B10").Font.ColorIndex = 3
End Sub
該過程可以使用With…End With語句來重新編寫,如下面的程式執行與上面程式完全一樣的操作:
Sub 設定格式2()
With Worksheets(“Sheet1”).Range("A1:B10").Font
.Name = "Arial"
.FontStyle = "Bold Italic"
.Size = 10
.Underline = xlUnderlineStyleSingle
.ColorIndex = 3
End With
End Sub
不能用一個With…End With語句來設定多個不同的物件,但可以將With塊放在另一個之中而產生巢狀的With語句,使用時必須在內層的With塊中使用完整的物件引用來指出在外層的With塊中的物件的成員,例如:
With MyObject ‘MyObject是一個物件的名稱
.Height = 100 ' 和 MyObject.Height 語句作用相同
.Caption = "Hello World" ' 和 MyObject.Caption語句作用相同
With .Font
.Color = Red ' 和 MyObject.Font.Color語句作用相同
.Bold = True ' 和 MyObject.Font.Bold語句作用相同
End With
End With
注:本示例及下面的兩個示例均來自於VBA幫助系統。
提示 一般來說,建議您不要跳入或跳出With塊。如果在With塊中的語句被執行,但是With或End With 語句並沒有執行,則一個包含對該物件引用的臨時變數將保留在記憶體中,直到您退出該過程。
使用With語句,不僅能避免您反覆輸入相同的程式碼,使您的程式程式碼更簡潔,而且更重要的是,能使您的程式執行得更快。在上面的“設定格式”程式中,可稍微感覺到兩個程式之間速度的差異,若資料量再加大,則這種執行速度之間的差異更明顯。
再舉兩個例子以加深對With…End With語句的認識。
下面的示例將在當前工作簿上的工作表Sheet1的單元格區域A1至C10中的單元格都填入數值30,單元格中的字型使用黑體格式,並將內部單元格顏色設定成黃色。
Sub FormatRange()
With Worksheets("Sheet1").Range("A1:C10")
.Value = 30
.Font.Bold = True
.Interior.Color = RGB(255, 255, 0)
End With
End Sub
下面是With語句巢狀使用的例子,將With語句巢狀使用將更具有效率。示例在工作簿Book1上的工作表Sheet1中的單元格A1中插入一個公式,然後格式化該單元格中的字型。
Sub MyInput()
With Workbooks("Book1").Worksheets("Sheet1").Cells(1, 1)
.Formula = "=SQRT(50)"
With .Font
.Name = "Arial"
.Bold = True
.Size = 8
End With
End With
End Sub
■ For Each … Next 語句
For Each…Next語句遍歷集合或陣列中的每個元素,重複執行語句中的程式碼。其語法為:
For Each <元素> In <集合/陣列>
[語句程式碼]
[Exit For]
[語句程式碼]
Next [元素]
其中,<元素>為必需的引數,表示用來遍歷集合或陣列中所有元素的變數;<集合/陣列>表示物件的集合或陣列的名稱;[語句程式碼]為可選引數,為對集合或陣列中每一元素執行操作的程式碼;[Exit For]語句為中途退出迴圈;Next後的[元素]可省略。
當集合或陣列中至少存在一個元素時,應會進入For Each…Next語句。首先針對集合或陣列中的第一個元素執行For Each…Next語句中的程式碼,然後針對第二個元素執行語句程式碼,當集合或陣列中的所有元素都執行完畢後,便會退出迴圈。如果在迴圈中的語句程式碼放置Exit For語句,執行到此語句時,便會退出迴圈;Exit For語句通常放在條件判斷語句中。
可以將一個For Each…Next語句放在另一個For Each…Next語句中組成巢狀的迴圈。在每個For Each…Next語句中的<元素>變數應該不同。
下面舉幾個例子來說明For Each…Next語句的用法。
下面的示例引自VBA幫助系統。它使用For Each...Next語句搜尋集合中的所有成員的Text 屬性,查詢“Hello”字串。在示例中,MyObject是面向文字的物件,並且是MyCollection集合的成員,這兩個名字都是為示範目的而使用的通用名稱,可用實際的物件賦值後在VBE編輯器中除錯。
Sub Sample()
Dim Found, MyObject, MyCollection
Found = False ' 設定變數初始值。
For Each MyObject In MyCollection ' 對每個成員作一次迴圈
If MyObject.Text = "Hello" Then ' 判斷Text屬性的值是否等於“Hello”
Found = True '如果Text屬性的值是否等於“Hello”,則將變數Found的值設成True
Exit For ' 退出迴圈
End If
Next
End Sub
下面的示例顯示當前工作簿中所有工作表的名字,用MsgBox函式顯示。如果當前工作簿中有3個工作表,則迴圈3次,相應地3次呼叫MsgBox函式。
Sub 顯示工作表名()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
MsgBox ws.Name
Next ws
End Sub
下面的示例關閉除當前工作簿之外的所有工作簿,在程式碼中使用了If…Then語句來判斷工作簿是否為當前工作簿,若不是當前工作簿,則關閉該工作簿。
Sub 關閉工作簿()
Dim wb As Workbook
For Each wb In Workbooks
If wb.Name <> ActiveWorkbook.Name Then wb.Close
Next wb
End Sub
下面的示例需要選在工作表中選擇某單元格區域後,再執行程式碼。程式將在所選單元格區域單元格中迴圈,並將每個單元格的值使用VBA的UCase函式轉換成大寫字母。
Sub 轉換成大寫()
Dim Cell As Range
For Each Cell In Selection
Cell.Value = UCase(Cell.Value)
Next Cell
End Sub
如何獲得幫助
在使用VBA編寫程式碼的過程中,難免會碰到問題,這時就需要幫助了。除求助於別人外,其實在Excel中就帶有很好的幫助系統,至少有以下三種方式。
■ 錄製巨集。通過錄制巨集,與所進行的操作過程相比較,能很好地學習如何使用物件、方法和屬性的相關知識。
■ 使用VBA幫助系統。這裡有關於Excel的物件、方法、屬性以及其它知識的詳細資訊。您可以在VBE編輯器的右上角“鍵入需要幫助的問題”文字框中輸入關鍵字後按Enter鍵,VBE將會顯示出搜尋到的所有相關的結果,您可以從中選擇想要看的主題。單擊所選擇的主題後,會彈出關於這個主題的資訊,您還可以在其中點選“參閱”、“示例”、“應用於”、“特性”等文字連結,檢視更詳細的資訊。
■ 使用“物件瀏覽器”。在VBE編輯器中,選擇選單“檢視——物件瀏覽器”或按F2鍵或選擇工具欄上的“物件瀏覽器”按鈕,將會顯示出“物件瀏覽器”視窗。在這裡,為每個可用的物件列出了所有的方法、屬性和事件,可檢視專案中的過程和常量。其中,飛行的小立方體圖標表明該成員是一個方法,亮的閃電圖標表明該成員是一個事件,索引卡圖標表明該成員是一個屬性。您可以選擇物件庫,在搜尋框中輸入想要搜尋的值。在搜尋結果視窗中是顯示出相匹配的文字,選擇一個物件後,在“類”視窗中顯示它的類,選擇一個類後,在右側將會顯示它的成員,包括方法、屬性和常量。在底部的視窗中,顯示了有關該物件的更多資訊。可以按F1鍵或單擊?號圖示直接進入該物件的幫助主題。
除了提供檢視Excel物件模型的方法外,“物件瀏覽器”也允許您檢視自已正在開發的工程的資訊,可方便地快速瀏覽工程中的所有元件及特定過程的詳細資訊。