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对象模型的方法外,“对象浏览器”也允许您查看自已正在开发的工程的信息,可方便地快速浏览工程中的所有组件及特定过程的详细信息。