版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
前言:相关术语
下面是一些快速浏览的术语,在讨论VisualBasic的对象及其功能时会遇到。
如果是从其它程序设计语言或者从使用ActiveX(从前称为OLE)术语转到
VisualBasic,那么这些主题对实现转换是有帮助的。
若是刚开始接触对象,可能会感到有点混乱。这是正常的,通过对将要遇到的这
些术语的快速浏览,就会对它们如何互相配合有个大概了解。随着在本章其余部
分接触更多的有关对象的信息,再回头浏览这些主题,就能将各部分零散的信息
形成一个总体。
由此开始
对象是被封装的一也就是说,它同时包含其代码和数据,这比传统的编写代码
方法更容易维护。
VisualBasic对象具有属性、方法和事件。属性是描述对象的数据。方法告诉
对象应做的事情。事件是对象所产生的事情,事件发生时可以编写代码进行史理。
在VisualBasic中,对象是由类创建的,因此对象被说成是类的一个实例。类
定义对象的界面,不管对象是否是公共的和在什么环境下建立的都是这样。类的
描述保存在类型库中,而且通过对象浏览器可以查看。
为了使用对象,必须在对象变量中保存其引用。绑定的类型决定使用对象变量访
问对象方法的速度。对象变量可以是后期绑定(最慢),或者是事前绑定。事前
绑定可以是DispID绑定或者vtable绑定(最快)。
属性和方法的集合称作界面。VisualBasic对象的缺省界面是支持所有三种绑
定窗体的双重接口。如果对象变量已经声明了类型(即Dim...Asclassnaire),
它将使用最快的绑定窗体。
除缺省界面外,VisualBasic对象能够为实现多态提供额外的界面。多态可以
操作不同种类的对象,而不用担心每个对象是什么类型。多界面是部件对象模型
(COM)的一个特征,它允许展开过时的程序,添加新功能而不需拆散老代码。
VisualBasic中的类也可以是数据识别的。通过直接绑定到一个外部数据源,
类可以作为数据使用者,或者通过从一个外部源提供数据,,它还可以作为其他
对象的数据源。
步入和谐的大厅
如果对所有这些似乎已经很熟悉了,那么可浏览本章的其余部分。如果不熟,也
不必担心,所有这些术语的说明都有策略地分布在本文中(并不是很凌乱地出
现)。
找出对象所属的类
通用对象变量(即,用AsObject声明的变量)可以保持许多不同类的变量。
同样,用VisualBasic内建的Form和Control类型声明的变量可以包含不
同类的窗体和控件。
在使用这些变量时,可能要根据对象的不同类而采取不同的操作一例如,某些对
象可能不支持个别的属性和方法。VisualBasic提供了两种方法:TypeOf关键
字和TypeName函数。
TypeOf关键字只能用在If...Then...Else语句中。必须在代码中直接包
含类名。例如,IfTypeOfMyControlIsCheckBoxThen。
TypeName函数更灵活些。代码中到处可以使用,并且因为它用字符串返回类名,
所以可将它与一字符串变量的值相比较。
使用字符串名调用属性和方法
大多数情况下,您可以在设计时发现对象的属性和方法,并且编写代码以处理它
们。但是,在少数情况下,您可能不知道某个对象的一些高级属性和方法,或者,
您可能只是想要这种灵活性,即允许最终用户在运行时指定属性或执行方法。
例如,请考虑下面的情况,某个客户端应用程序,它通过传递一个运算符到服务
器程序来计算由用户输入的表达式。现在,假定您要经常性地向需要新运算符的
服务器添加新函数。那么,不幸的是,在客户端应用程序能够使用新的运算符之
前,您需要重新编辑和重新发布它。为了避免这种情况,可以使用CallByName函
数把新运算符当作字符串来传递,而不需要更改应用程序。
CallByName函数允许您使用一个字符串在运行时指定一个属性或方法。
CallByName函数的用法如下:
Result=Cal1ByName:0bject,ProcedureName,CalIType,Arguments())
CallByName的第一个参数包含要对其执行动作的对象名。第二个参数,
ProcedureName,是一个字符串,包含将要调用的方法或属性过程名。CalIType参
数包含一个常数,代表要调用的过程的类型:方法(vbMeihod)、propertylet
(vbLet)、propertyget(vbGet),或propertyset(vbSet)o最后一个参数是
可选的,它包含一个变量数组,数组中包含该过程的参数。
假定您有一个服务器应用程序,MathServer,并且它具有一个新的函数
SquareRooto该应用程序中有两个TextBox控件:Textl包含要计算的表达式;
Text2用于输入该函数的名称。要对Texll中的表达式调用SquareRoot函数,
您可以在一个命令按钮的Click事件中使用下面的代码:
PrivateSubCommand1Click()
Textl.Text=CallByNamc(MathScrver,Tcxt2.Text,vbMcthod,
Textl.Text)
EndSub
如果用户在Textl中输入〃64/4〃,在Text2中输入“SquareRoot”,则上
面的代码将调用SquareRoot函数(要求一个必需的参数,它是一个包含将要计
算的表达式的字符串),并且在Textl中返回"4〃(16或64/4的平方根)。
当然,如果用户在Text2中输入了一个无效的字符串,或者该字符串包含一个
属性名而不是方法名,或者该方法要求附加的必需的参数,那么将会产生一个运
行时错误。可以猜到,当您使用CallByName来预处理这些或其他的错误时,需
要添加强健的错误处理程序代码。
尽管CallByName函数在某些情况下可能很有用,但是,还是需要在衡量其实用
性时考虑对性能可能的影响一同后期绑定相比,使用CallByName来调用一个
过程只会稍稍慢一点儿。如果您正调用的函数将要被重复调用很多次,例如在一
个循环内部,则CallByName将会对性能产生严重的影响。
对一个对象执行多个动作
经常需要在同一对象中执行多个不同的动作。例如,需要对同一对象设置几个属
性。途径之一是使用多条语句。
PrivateSubFormLoad()
Command1.Caption=〃()K"
Commandl.Visible=True
Command1.Top=200
Commandl.Left=5000
Commandl.Enabled=True
EndSub
应注意的是所有这些语句使用同一个对象变量Commandl。通过使用With...End
With语句,可使该代码更容易编写、阅读和更有效地运行。
PrivateSubForm_Load()
WithCommand1
.Caption=〃0K〃
.Visible=True
.Top=200
.Left=5000
.Enabled=True
EndWith
EndSub
还可以通过将With...EndWith语句置入另一个With...EndWith语句内实现
嵌套的With语句。
使用缺省属性
很多对象具有缺省属性。使用缺省属性能够简化代码,因为设置属性值时,不必
详细指明该属性。Value是对象缺省属性,这两个语句是等价的:
object=20
和
object.Value=20
为了说明它们是如何工作的,在窗体上绘制命令按钮和文本框。将下列语句添加
到命令按钮的Click事件中:
Textl="hello"
运行该应用程序,并单击命令按钮。因为Text是文本框的缺省属性,所以文本
框将显示文本“hello”。
通过对象变量使用缺省属性
当对象的引用被保存在对象变量中时,仍然可以使用缺省属性。下面的代码段说
明了这一点。
PrivateSubCommandl_Click()
DimobjAsObject
'把对Textl的引用放入对象变量。
Setobj=Textl
'设置缺省属性(Text)的值。
obj=〃hello〃
EndSub
在上面的代码中,obj="hello”和obj.Text="hello”是完全相同的。
通过Variants使用缺省属性
当对象引用保存在Variants类型的变量中,而不是在对象变量中时,访问玦省
属性是不同的。这是因为Variants能包含多种不同类型的数据。
例如,能够使用Variants中的引用读取Textl的缺省属性,但是试图将字符
串“goodbye”赋给缺省属性的做法是行不通的。相反,它将用该字符串代替该
对象引用,并改变Variants的类型。
为了说明这一点,以前面示例为例,在命令按钮的Click事件中输入下面的代
码:
PrivateSubCommand1_C1ick()
DimvntAsVariant
’设置缺省属性(Text)为“hello”。
Textl="hello”
'把对Textl的引用放入Variants。
Setvnt=Textl
'显示Textl的缺省属性,并且给出
'Variants包含对象引用。
MsgBoxvnt,,“"Object?〃&IsObject(vnt)
'试图设置Textl的缺省属性。
vnt="goodbye”
MsgBoxvnt,,“IsObject?〃&IsObject(vnt)
EndSub
当运行该应用程序并单击命令按钮时,首先出现的信息框显示Textl缺省属性
的当前值“hello”,它通过查看Textl可得到证实。信息框的标题证明
Variant包含有一个木象引用一即对Textl的引用。
当单击信息框中的“确定”按钮时,“goodbye”赋给该Variants,并破坏了
Textl的引用。接着显示另一信息框,并显示该Variants的内容一正如所看
到的那样,它与Textl.Text的当前值不匹配。
信息框的标题证明,Variants不再包含对象引用一它现在包含字符串
“goodbye”。
详细信息有关Variants和其它数据类型的详细信息,请参阅“编程基础”中
的“变量、常数和数据类型概述”。
使用对象和Variants的其它内容将在“VisualBasic集合对象”中讨论。
创建对象数组
正象声明和使用任何数据类型的数组那样,也能够声明和使用对象类型的数组。
这些数组既可以是固定大小的,也可以是动态的。
窗体变量数组
与声明其它任何类型数组的方法相同,可以使用Private、ReDinuStatic
或Public声明窗体数组。如果数组声明使用了New关键字,则当使用该数组
的元素时,VisualBasic将自动为数组中每个元素创建一个新窗体实例。
PrivateSubCommand1Click()
DimintXAsInteger
DimfrmNew(1To5)AsNewForml
ForintX=1To5
frmNew(intX).Show
frmNcw(intX).WindowStatc=vbMinimizcd
'为了不让它们第一次以正常大小出现而
'创建最小化窗体,可改变
'上面两行的顺序。
Next
EndSub
按命令按钮执行上述代码,将建立五个最小化的Forml实例。
注意如果查看任务栏,可看到六个Forml.额外的Forml实例不是最小
化的一它是刚开始使用的那个。
控件变量数组
与声明任何其它类型数组的方法相同,可以使用PrivatesDim、ReDim>Static
或Public声明控件数组。然而与窗体数组不同,控件数组不能使用New关键
字声明。例如I,可以声明数组为特定的控件类型:
ReDiinActiveImages(10)AsImage
当声明数组为特定控件类型时,只能将该类型的控件赋给数组。例如,在前面的
声明中,只能将图像控件赋给该数组一但是这些图像控件可以来自不同的窗体。
将其与内置Controls集合进行比较,内置Controls集合能包含很多不同类型
的控件一所有这些控件必须在同一窗体中。
另外,可以声明类属控件变量数组。例如,若要跟踪拖放到某一特定控件中的每
个控件,而且不允许任何控件被拖放多次。通过对控件变量的动态数组的管理可
以做到这点,只要让该动态数组包含每个被拖放控件的引用即可。
PrivateSubListl_DragDrop(SourceAsVB.Control,_
XAsSingle,YAsSingle)
DimintXAsInteger
StaticintSizeAsInteger
StaticctlDroppcdOAsControl
ForintX=1TointSize
'如果数组中有被拖放的控件,则它
'己经被拖放到这儿一次。
IfctlDroppedJintX)IsSourceThen
Beep
ExitSub
EndIf
Next
'扩展数组。
intSize=intSize+1
ReDimPreservectlDropped(intSize)
'保存被拖放控件的引用。
SetctlDropped(intSize)二Source
'给列表框添加控件名。
List1.AdditemSource.Name
EndSub
该示例使用Is操作符将控件数组中的变量和控件参数进行比较。Is操作符可
用来测试VisualBasic对象引用的一致性:如果两个不同引用的比较结果为同
一对象,Is操作符返回True。
该示例还使用Set语句将Source参数中的对象引用赋予数组中的元素。
详细信息请参阅《语言参考》中的“19操作符”。
在“编程基础”的“数组”和“动态数组”中介绍数组。
关于跟踪对象的更简易的方法,请参阅本章后面的“创建对象集合”。
创建对象集合
集合提供了跟踪对象很有用的方法。与数组不同,当增加和删除集合对象的成员
时,它的大小不会改变。
例如,若要跟踪拖放到某一特定控件中的每个控件,并且不允许多次拖放任何控
件。通过对集合进行管理可做到这点,该集合包含每个被拖放控件的引用:
PrivateSubListlDragDrop(SourceAsVB.Control,
XAsSingle,YAsSingle)
DimvntAsVariant
StaticcolDroppcdControlsAsNewCollection
ForEachvntIncolDroppedControls
'如果集合中有被拖放的控件,则
'它己经被拖放到这儿一次。
IfvntIsSourceThen
Beep
ExitSub
EndIf
Next
'保存被拖放控件的引用。
colDroppedControls.AddSource
'在列表框中添加控件名。
Listl.AdditemSource.Name
EndSub
该示例使用Is操作符将colDroppedControls集合中的对象引用和包含被拖
放控件引用的事件参数进行比较。Is操作符可用来测试VisualBasic对象引
用的一致性:如果两个不同引用的比较结果为同一对象,1s操作符将返回True.
该示例还使用集合对象中的Add方法将对被拖放控件的引用放到集合中。
与数组不同,集合本身也是对象。变量colDroppedControls被声明为AsNew,
因此在代码中变量第一次被引用时将创建该集合类的实例。由于变量被声明为
Static,因此当事件过程结束时,该集合对象不会消失。
详细信息请参阅《语言参考》的“Is操作符”。
本章后面的“VisualBasic集合对象”中将讨论Collection对象的属性和方
法。
有关上述代码与需要使用数组的代码的比较,请参阅本章前面的“创建对象数
组”。
要了解如何在自己集合类中包括集合对象,建立更强健的集合,请参阅本章后面
的“创建自己的集合类”。
本章前面的“VisualBasic中的对象”讨论如何建立和破坏对象。
VisualBasic集合对象
集合是方法将一系列相关的项构成组的一种方法。VisualBasic中集合可用于
跟踪很多事情,例如程序中加载的窗体(窗体集合),或者在窗体中的所有控件
(控件集合)。
VisualBasic提供的类属Collection类可用来定义自己的集合。需要多少集
合对象,就可以建立多少Collection对象一即Collection类的实例。还可
使用集合对象作为自己的集合类和对象模型的基础,它将在本章后面的“创建自
己的集合类”和“对象模型”中讨论。
例如,集合是跟踪多窗体的最好方法。在“创建用户界面”中的“多文档界面
(MD1)应用程序”里讨论用户可以打开任何数目文档窗口的应用程序。以下代码
段演示如何使用集合市象的Add方法,对用户建立的MDI子窗体列表进行管
理。该代码假定已经存在一个名为mdiDocument的窗体,其MDIChild属性设
置为True。
'父MDIForm中的模块级集合。
PubliccolDocumentsAsNewCollection
’建立新的MDI子文档窗体的代码。
PrivateSubmnuFileNewO
DimfAsNewmdiDocument
StaticintDocumentNumberAsInteger
intDocumentNumber=intDocumentNumber+1
’下面的语句创建窗体。
f.Caption="Document/'&intDocumentNumber
'给集合添加对象引用。
colDocuments.Addf
f.Show
EndSub
colDocuments的作用象是内置窗体集合的一个子集,它只包含窗体
mdiDocument的一些实例。每添加一个新窗体,自动调节集合的大小。可使用For
Each...Next在集合内进行迭代。如果赋予窗体一个可以检索的键,那么可提
供一文本字符串作为Add方法的第二个参数,如本节后面部分所述。
在变量colDocuments的声明中,New关键字导致当该变量第一次被引用时,在
代码中创建集合对象。因为集合是类,而不是数据类型,所以必须建立集合实例,
并且在变量中记录对该实例(对象)的引用。
象其它任何对象一样,当包含其引用的最后一个变量被设置成Nothing或不可
见时,Collection对象将被撤消。它包含的所有对象引用将被释放。因此,变
量colDocuments在父MDIForm中声明,于是它将存在于程序存活期中的整个
过程。
注意如果使用集合来跟踪窗体,当窗体被卸载之后,应使用集合的Remove
方法从集合中删除该市象引用。只要对该窗体的引用仍然存在,就不能收回窗体
使用的内存,并旦Collection对象保存的引用象对象变量中的引用一样完好。
集合对象的构成
Collection对象将每一项存储于Variants对象中。于是,能够添加到
Collection对象里的内容列表就和能够存储到Variants中的内容列表是相同
的。这包括标准数据类型、对象和数组一但不包括用户定义类型。
不管Variants中存储的是什么,它都占16字节,因此使用Collection对■象
不如使用数组的效率高。然而,不能RcDim一个Collection对象,ReDin
Collection对象能够使代码更清楚、更容易维护。此外,集合对象按键能进行
快速的查找,而数组却不能。
注意准确一点说,即使是把数据存储在其它地方,Variants也总是只占16个
字节。例如,如果把字符串或数组赋给Variants,Variants将包含一个指向字
符串和数组数据备份的指针。在32位系统中,指针只使用了Variants的4个
字节,而且Variants中实际上不存在数据。
若要存储一个对象,Variants将包含该对象引用,就象对象变量所做的一样。
对字符串和数组来说,也只使用Variants的4个字节。
数字数据类型存储在Variants中。不管什么样的数据类型,Variants仍然占
16个字节。
除了Variants大小之外,还有很多情况需要使用Collection对象来存储上面
列出的所有数据类型。应该知道进行权衡:使用Collection对象能够编写清楚
且容易维护的代码一所花费的仅是将一些项存储在Variant中。
集合对象的属性和方法
每个集合对象都有属性和方法,使用它们能够插入、删除和检索该集合中的项。
属性或方法描述
Add方法给集合添加项。
Count属性返回集合中项的数目。只读。
Item方法通过索引或关键字,返回项。
Remove方法通过索引或关键字,从集合中删除项。
这些属性和方法仅仅是集合最基本的功能。例如,要确保集合只包含一种本象,
Add方法并不能检查将要添加到集合里的对象类型。通过建立自己的集合类能够
提供更强健的功能,以及额外的属性、方法和事件,正如本章后面的“创建自己
的集合类”中所述。
集合中的增加、删除和检索的基本功能需要关键字和索引。关键字是一个String
的值。它可以是能转换成字符串的名字、驾驶执照号、社会安全号或者简单的整
数。Add方法允许将关键字与项相关联,如本节后面部分所述。
索引是长整型,介于1和集合中项的数目之间。使用before和after命名
的参数,可以控制项索引的初始值,但是随着其它项的增加和删除,其值会发生
改变。
注意索引从1开始的集合称为基于1,如“VisualBasic中的集合”中所述。
使用索引能够在进行集合的项中迭代。例如,假定变量mcolEmployees中包含
对集合对象的一个引用,下列代码使用两种方法把Employee对象集合中所有雇
员的薪水提高10%o
DimIngCtAsLong
ForIngCt=1TomcolEmployees.Count
mcolEmployees(IngCt).Rate=
mcolEmployeesUngCt).F^ate*1.1
Next
DimempAsEmployee
ForEachempInmcolEmployees
emp.Rate=emp.Rate*1.1
Next
提示为改善性能,应使用ForEach对Collection对象中的项进行迭代。使
用ForEach迭代要比使用索引快很多倍。这并不是对所有集合都正确一它取
决于集合内部存储数据的方法。
给集合添加项
Add方法用于将项添加到集合。语法是:
SubAdd(itemAsVariant[,keyAsVariant][,beforeAsVariant]
[,afterAsVariant])
例如,使用工作定单ID属性作为关键字,将工作定单对象添加到工作定单集合
里,代码可编写为:
colWorkOrders.AddwoNew,woNew.ID
这里假定ID属性是字符串。如果属性是数字(例如Long),则应使用CStr函
数将它转换成关键字所要求的字符串值:
colWorkOrders.AddwoNew,CStr(woNew.ID)
Add方法支持命名的参数。为了添加一项作为第三个元素,代码可编写为:
colWorkOrders.AddwoNew,woNew.ID,after:=2
可以使用before和after命名的参数管理有斤的对象集合。例如,
before:=l将在集合的开始插入一项,因为集合对象是基于1的。
从集合中删除项
Remove方法用于从集合中删除项。语法是:
object.Removeindex
index参数可以是所删除项在集合中的位置,或者是该项的关键字。如果集合中
第三个元素的关键字是“W017493”,则可使用这两条语句中的任何一条删除它:
colWorkOrders.Remove3
一或一
colWorkOrders.Remove〃W'017493”
从集合中检索项
Item方法用于从集合中检索特定项。语法是:
[Set]variable=object.Item(index)
和Remove方法一样,index可以检索项在集合中的位置,或者是该项的关键
字。使用Remove方法中的相同示例,这两条语句中的任一条都可检索集合中的
第三个元素:
SetwoCurrent=colWorkOrders.Item(3)
一或一
SetwoCurrent=colVorkOrders.Item(z/W017493,z)
如果使用整数作为关键字,在将它们传递到Item或Remove方法之前,必须使
用CStr函数将其转换成字符串。通常集合对象都假定整数是索引。
提示Collection对象不能决定所传递的值是索引还是键。如果想把值解释为
键,并且包含该值的变量是除String以外的任何值,可以使用CStr函数进行
转换。如果想把值解释为索引,并且包含该值的变量不是整型数据类型中的一种,
使用CLng进行转换。
Item是缺省方法
对于集合对象来说,Item方法是缺省方法,因此当访问集合中的项时,可忽略
它。所以前面的代码示例也可以写成:
SetwoCurrent=colWorkOrders(3)
一或一
SetwoCurrent=colVorkOrders(/,W017493,/)
重点当添加和删除集合对象元素时,集合对象会自动地维护其数字索引编号。
因此给定元素的数字索引随之改变。不能在程序中存储数字索引值,并用它检索
同一个元素。为达到该目的,应使用键。
使用Item方法调用属性和方法
为了使用对象引用,不能从集合中检索该对象引用,并把它放到对象变量中。当
对象仍然在集合里时能够使用其引用。
例如,假设上述代码中的WorkOrder对象具有Priority属性。下面的语句都
可用于设置工作定单的优先级:
colWorkOrders.TtemC,W017493,/).Priority=3
colWorkOrders(z,W017493/z).Priority=3
可行的原因是VisualBasic要从左到右计算表达式。当遇到Item方法时一
显式的或隐式的一VisualBasic为指定的项(此时是键为W017493的
WorkOrder对象)取得一个引用,并使用该引用计算该行的其余部分。
提示如果想调用集合中对象的多个属性或方法,首先将该对象引用复制到一个
强类型的对象变量中。把引用放到一个强类型的对象变量中,然后使用,比使用
集合里对象的引用要快(例如,DimwoCurrentAsiVorkOrder),因为Collection
对象是把项存储在Variants中。Variants中的对象引用总是最后绑定。
详细信息对很多一般的程序设计任务来说,集合对象也是数组的很有用的可选
方案。请参阅“再论编程”中的“用集合替代数组”。
VisualBasic提供很多内置集合。有关它们与集合对象的比较,请参阅"Visual
Basic中的集合”。
VisualBasic中的集合
什么是集合?在"VisualBasic集合对象”中,集合定义为一种把有相关的对
象分组的方法。这种定义留下很多解释余地,与其说它是一种定义还不如说它是
一个概念更合适。
实际上,当比较集合时就会发现,VisualBasic所提供的各种集合之间都有很
大的差别。例如,下列代码会引起错误:
DimcolAsCollection
Setcol=Forms'错误!
这是怎么回事?Forms集合是集合,变量col也声明为Collection,为什么不
能将指向Forms的引用赋给变量col?
其原因是Collection类和Forms集合都不是多态的,即它们不能相互交换,
因为是从各自的代码库开发的。它们没有相同的方法,没有用相同的方法存储对
象引用,或者没有使用相同种类的索引值。
这使得Collection类名似乎是多余的,因为它仅仅代表许多可能实现集合方法
的一种。该主题探讨一些实现方法的差别,后面将会遇到这些差别。
基于0和基于1的集合
集合是基于o还是基于1,要取决于开始索引是哪一个。可以猜想,前者的意
思是集合中第一项的索引为0,后者的意思是集合中第一项的索引为lo基于0
的集合示例是Forms和Controls集合。基于:的集合的示例是集合对象。
VisualBasic中旧的集合大多是基于0的。而新添加的集合大多基于1。基于
1的集合使用时更加直观,因为索引的范围是从1到Count,其中,Count是
能返回集合中项数目的属性。
对应基于0的集合索引来说,其范围则是从0到Count-1o
索引和键值
正象VisualBasic中的Collection对象那样,VisualBasic中很多集合可
以使用数字索引或字符串键来访问其中的项。(然而,VisualBasic中的
Collection对象不用韦定键就能添加项。)
相反,Forms集合只能使用数字索引来访问。这是因为没有唯一的字符串值与窗
体关联。例如,多个窗体可以有相同的标题,或者加载的多个窗体有相同的Name
属性。
添加和删除项
在能否向集合中添加项这点上,集合之间也是有区别的,如果可以,这些项是如
何添加到集合中的。例如,不能使用VisualBasic代码向Printers集合添加
打印机。
因为Collection对象是一般性程序设计工具,它比其它集合更加灵活。它具有
Add方法可以将项添加到集合里,也有Remove方法可以将项从集合中删除。
与之形成对比的是,Forms集合获取窗体的唯一方法是加载窗体。如果使用New
操作符建立窗体,或者通过引用一个声明为AsNew的变量建立窗体,那么该窗
体是不能被添加到窗体集合里的,除非使用Load语句进行加载。
Forms和控件集合没有Remove方法。可以使用Load和Unload语句间接的向
这些集合中添加和从这些集合中删除窗体和控件。
窗体集合中的成员
正如上面所述,窗体在加载之前不能添加到Forms集合中。因此Forms集合的
最准确的说明是:它包含的是程序中当前加载的所有窗体。
即使它不完全准确。如果工程中使用MicrosoftForms(为了与Microsoft
Office兼容被包括的),就会发现这些窗体都在一个名为UserForms的单独集
合里。因此该Forms集合所包含的就是程序中当前加载的所有VisualBasic
窗体。
而Collection类十分准确指定的内容是:能够存储到Variants里的任何东
西。于是集合对象能包含对象或者整数,但不能包含用户定义类型。
遗憾的是,该说明的覆盖范围很广一集合类给定的一个实例能够存储任何数据
类型、数组和对象的混合组合。
提示正如“创建自己的集合类”中所述,建立自己的集合类的最重要原因是能
够控制自己的集合中的内容一称为类型安全性概念。
集合的枚举
可以使用ForEach...Next对集合中的项枚举,而不用担心集合是基于0还
是基于io当然,这很难作为集合的一个定义特性,因为.VisualBasic也允许
使用ForEach...Next对数组中的项枚举。
使ForEach...Next能工作的是一个称为enumerato的很小的对象。枚举算
子记录集合中项的位置,并在需要时返回下一项。
枚举数组时,在运行中VisualBasic创建一个数组枚举算子对象。集合具有自
己的枚举算子对象,它也是需要时创建的。
枚举算子不会跳过项
VisualBasic中集合的枚举算子不会跳过项。例如,假设枚举一个包含〃A〃、
〃B〃和〃C〃的集合,并且进行枚举时删除了〃B〃,则在操作时VisualBasic不
会跳到〃C〃上。
枚举算子可能不捕捉添加的项
当枚举集合时,如果给集合添加了项,一些枚举算子将能包含添加的项,而一些
枚举算子则不会。例如,枚举Forms集合时就不枚举刚加载的任何窗体。
如果将它们添加到集合末尾,则在枚举时集合,对象就能枚举添加的项。因此下
列循环永远不会终止(即直到按CTRL+BREAK组合键):
DimcolAsNewCollection
DimvntAsVariant
col.Add"Endless”
col.Add"Endless”
ForEachvntIncol
MsgBoxvnt
col.Add"Endless”
Next
另一方面,添加到集合开始的项不会包含在枚举里。
DimcolAsNewCollection
DimvntAsVariant
col.Add"Willbeenumerated”
ForEachvntIncol
MsgBoxvnt
'在开始处添加项。
col.Add"Won'tbeenumerated”,Before:=1
Next
为什么需要枚举算子?
每次ForEach...Next开始时,通过发出一新枚举算子,集合允许嵌套的枚
举。例如,假定在变量mcolStrings中有一个Collection对象的引用,并且
该集合只包含字符串。下列代码打印两个不同字符串的所有组合:
DimvntlAsVariant
Dimvnt2AsVariant
ForEachvntlTnmcolStrings
ForEachvnt2InmcolStrings
Ifvntl<>vnt2Then
Debug.Printvntl&〃〃&vnt2
EndIf
Next
Next
详细信息请参阅本章后面的“创建自己的集合类”。
查找对象信息
对象浏览器是基于类型库的,类型库是包含属性、方法、事件、命名常数以及其
它许多方面信息在内的、类的详细描述的资源。
VisualBasic为创建的类建立类型库信息,为其包含的对象提供类型库,并且
允许访问其它应用程序提供的类型库。
可以使用对象浏览器显示工程和库中的有效的类,包括自己定义的类。用这些类
所创建的对象都拥有同样的成员一属性、方法和事件一这些都可以在对象浏览
器中看到。
图9.1对象浏览器
要显示对象浏览器,请
•从“查看”菜单选择“对象浏览器”。
一或一
按F2键。
」或一
在工具栏上单击“对象浏览器”。
按照缺省规定,对象浏览器不能接连接其它窗口。这样可以使用CTRL+TAB在
对象浏览器和代码窗口之间切换。也可以通过在对象浏览器中单击右键打开上下
文菜单,并单击'、可连接的〃改变这种情况。
注意当对象浏览器处于可以连接状态时,不能使用CTRL+TAB从代码
窗口切换至对象浏览器。
以下主题详细讨论对象浏览器的功能。
•对象浏览器的内容对象浏览器显示类及其成员。提示对象内容的描述性
的文字,并给出函数模板。
•查找和浏览对象即使只记得名字的一部分,也可以找到对象及其成员。
•添加对象的描述为类及其成员添加的描述可以帮助对类的使用。
•在过程之间移动可以在工程内找到模块和过程,并跳转到其代码处。
•浏览其它应用程存的对象可以在自己的程仔中使用其它应用程序中的对
象;对象浏览器将显示其它应用程序所提供的自动化对象。
添加对象的描述
可以使用对象浏览器给自己的过程、模块、类、属性和方法添加描述及
"HelpContextIDs"o使用自己的类时就能找到这些有用的描述。
注意也可以从“工具”菜单中使用“过程属性”对话框给属性、方法和事件添
加描述。
要输入描述字符串,并将类及其成员与帮助主题进行链接,请按照以下步骤执
行:
1.按F2键打开“对象浏览器”。在“属性/库”框中选择所需的工程。
2.在“类”列表中,在类名处单击右键弹出上下文菜单,然后单击“属性”
打开“成员选项”对话框。
或者,也可以在“成员”列表中对已添加到类中的属性、方法或事件名单
击右键。在上下文菜单中,单击“属性”。如果成员是Private的或
Friend的,则打开“成员选项”对话框。如果成员是Public的一即类
的界面部分一将代之以打开“过程属性”对话框。
注意这两种对话框的区别是“过程属性”对话框有一个“高级”按钮可
用来将一个成员指定为该类的缺省成员,这一点将在本章后边的“使属性
或方法成为缺省的”中进行描述。
3.为了当这个类或成员在“对象浏览器”中被选中,并单击“?”时,该帮
助主题的上下文标识符能被显示,应在“帮助上下文标识符”框中键入该
帮助主题的上下文标识符。
注意可以创建一个帮助义件以备自用,并将主题连接到自己的类及其成
员中。如果希望为自己的工程指定一个帮助文件,可在“工程”菜单中打
开“工程属性”对话框,使用其中的“通用”选项卡。
4.在“描述”框中,键入关于该类或成员的简短描述。
5.单击“确定”返回“对象浏览器”。键入的描述字符串应该出现在浏览器
底部的描述面板中。
6.对每一个类和其中的的每一个成员重复第2步到第5步。
注意不能为枚举添加浏览器字符串或帮助主题。
详细信息枚举在“再论编程”中的“通过枚举使用常数集进行工作”中进行介
绍。
类:将用户定义类型和过程组织在一起
用户定义类型是一个使相关数据项成组的强大工具。例如,假设此处要定义名为
udtAccount的用户定义类型:
PublicTypeudtAccount
NumberAsLong
TypeAsByte
CustomerNameAsString
BalanceAsDouble
EndType
可以声明一个udtAccount类型的变量,分别给各个字段赋值,然后将整个记录
传递给打印它的过程,并将其保存至数据库中,对其执行计算,验证各字段的数
U/古a,笺笺。
用户定义类型尽管功能强大,但也给编程者带来了一些问题。例如所创建的提款
过程可能出错,如果当提款超过帐上余额,程序中又没有措施防止其它代码对余
额字段减时就会出错。
换句话说,过程和用户定义类型的结合效果取决于规则、内存和维护代码的编程
者的知识水平。
对象:具有态的用户定义类型
面向对婴的编程通过将数据和过程结合成一个单一实体解决了上述问题,如图
9.5所示。
图9.5对象使数据和过程相结合
当用户定义类型udtAccount变成Account类时,其数据变成了私有型,访问
它们的过程移动类中并变成了属性和方法。这就是所谓的封装的意思一这就是
说,对象是一个包括了代码和数据的单兀(如果愿息,也可称其为密封舱)。
当从Account类创建一个Account变量时,访问其数据的唯一途径就是通过构
成其界面的属性及方法。以下的代码段说明在Account类中的过程是如何支持
封装的:
'帐户余额对外界代码是隐藏的。
PrivatemdblBalanceAsDouble
'帐户余额的只读属性允许外部的代码
'获取帐户余额。
PublicPropertyGetBalance()AsDouble
Balance=mdblBalance
EndProperty
'提取存款的方法改变了帐户的余额,
’但仅限于不发生透支错误的情况。
PublicSubWithdrawal(ByVaiAmountAsDouble)
IfAmount>BalanceThen
Err.RaiseNumber:=vbObjectError+2081,
Description:=/,0verdraft/,
EndIf
mdblBalance=mdblBalance-Amount
EndSub
现在,暂不要考虑如何将过程放进类中,也不要考虑如何理解属性过程和私有变
量的语法。要记住的重点就是可以定义一个对象来封装数据和确保数据的可靠。
有了Account对象,就永远不必关心是否调用了正确的过程更新帐户,因为可
以调用的那些过程都已经组装进对象中了。
详细信息”定制窗体类”部分将属性和方法的创建放入已熟悉的框架。然后,
“给类添加属性和方法”部分将解释其语法。
可以参阅“再论编程”中的“创建自己的数据类型”中关于用户定义类型的内
容C
关于子过程和函数过程的详细信息,请参阅第五章“编程基础”中的“过程概述
a
o
定制窗体类
如果说创建类的历史与使用VisualBasic编程的历史一样长,也许会感到惊
奇。但这是真的:Fornl,每次开始一个工程都要碰到的这个老相识,实际上就
是一个类。
为了说明这一点,打开一个新的“标准EXE”工程。添加一个按钮到Froml,并
在单击事件中放置如下的代码:
PrivateSubCommand!.ClickO
DimfAsNewFornl
f.Show
EndSub
按F5键运行这个工程,并单击该按钮。啊!出现了Forml的另一个实体!单
击其中的按钮,又有另一个窗体!所创建的每一个实体看上去都是一样的,并且
有同样的表现,因为它们都是Forml类的实体。
这里发生了什么事情?
如果己阅读了“编程基础”中的“使用对象”,就会知道一个被声明成“As
New”的对象变量,在弋码中第一次被引用之前所包含的是“Nothing"。当变
量第一次被使用时,VisualBasic注意到其中包含特定数值“Nothing",就要
创建一个该类的实例(这也是一件好事,否则f.Show将引起错误)。
隐藏全局变量的Me和My
也许会有点奇怪,在代码中怎样就能引用Forml,它好象是一个对象变量。这并
不离奇,VisualBasic为每一个窗体类创建了一个隐藏的全局对象变量。看起
来就象VisualBasic向工程添加了下列声明:
PublicFormlAsNewForml
当选择Forml作为启动对象时,或者在代码中键入Forml.Show,就引用了这个
隐藏的全局对象变量。因为它被声明为“AsNew”,因此当代码中第一次使用这
个预先声明的变量时,将创建Forml类的一个实例。
隐藏该声明的理由是每次更改窗体的Name属性时,VisualBasic都要改变它。
通过这种方法,隐藏的变量总是与窗体类有同样的名字。
一个小问题
在上述练习中创建的Forml的哪一个实例与隐藏的全局变量相关联?如果认为
是第一个,则是对的。Forml是工程的缺省启动对象,对VisualBasic而言它
和在代码中使用预先声明的全局变量一样。
提示在一个窗体卸载后,总是必须将对该窗体的任何引用设置为“Nothing”,
以便释放其所使用的内存和资源。最经常被忽略的引用是这个隙臧的全局窗体变
量。
关于Forml的其它实例
在“编程基础”中,已经了解到要引用一个对象,需要一个对象变量,一个对象
只有当至少存在一个市象变量包含对它的引用时才能存在。那么,是什么使得其
它的实例能够存在呢?
I'orml的第二个实例,及以后的其它实例,都有一个对象变量,只要是调用其
Show方法时就一直存在。然后该变量退出可见范围,并且被设置为“Nothing”。
但是VisualBasic保持一个名为Forms的特殊的集合,这可以在第六章“创
建用户界面”中的“再论窗体”中看到。该Forns集合包含了对工程中每一个
己被装载的窗体的引用,所以总是可以找到和控制它们。
注意正如所了解的那样,并不是对所有的类来说都是这样。例如,自己设计的
类将不会有隐藏的全局变量或全局集合来跟踪它们一这些是窗体类的特定功
能.但是,可以声明自己的全局变量,也可以创建自己的集合一就象在“创建
自己的集合类”中所描述的那样。
窗体类的属性、方法和事件
第一次为窗体类添加属性时,可以直接把一个命令按钮(或其它的控件)拖放到
Forml中。这样就添加了一个只读的Command1属性给窗体类。此后,当需要调
用命令按钮的方法或属性时就是引用Form1的这一属性:
Command1.Caption="ClickMe〃
在改变窗体中任何控件的Name属性时,VisualBasic悄悄地改变了只读属性
的名称以使二者匹配。
如果以前练习示例的工程还打开着,可以按F2键打开对象浏览器能见到
Commandl属性。在''工程/库〃框中,选中Projectl,可以在类窗格中见到
Formic向下滚动成员窗格直到发现Commandl,选中它。
Commandl边上有一个属性符号。从说明窗格中可以知道它是WithEvents属性。
正如在“向类中添加事件”中所述,这表示属性(或对象变量)具有与之相关的
事件过程。作为事件过程之一的Commandl_Click()也许是自编写Visual
Basic代码以来的第一个。
其它
把控件放到窗体上不是向窗体类添加成员的唯一方法。还可以在建立新变量和过
程时添加定制的属性、方法和事件。
为了说明这点,请把下列代码添加到Forml的声明部分:
1Forml类的Comment属性
PublicCommentAsString
请把下列代码添加到Forml的Click事件:
PrivateSubForm_Click()
MsgBoxComment,,〃Mycommentis:
EndSub
最后,如下所示向Conmandl_Click()事件过程添加一行代码:
PrivateSubCommand1.Click()
DimfAsNewFornl
f.Comment二TnputBox(//What,smycomment?z,)
f.Show
EndSub
按F5键运行该工程。单击Commandl,出现输入框时,输入一些有趣的注
释然后单击0K。当Forml的新实例出现时,单击它以显示其Comment属
性。
单击第一个Forml实例,可以看到其Comment属性是空白的。这是由于Visual
Basic把该实例当作启动对象,不可能有机会设置其Comment属性。
窗体间可以相互调用其方法
如果仔细观察可以发现,添加到Forml类中代码并不设置该对象本身的
Comment属性一它只没置已被创建的Forml新实例的Comment属性。
设置其它窗体的属性和调用其它窗体的方法是一项非常有用的技术。例如,一个
MDIForm在打开一个新的子窗口时可以通过设置其属性、调用其方法来对它初始
化。
还可将此技术用于在窗体之间传递信息。
提示可以为窗体创建定制的事件。本章后面的“向窗体中添加事件”中将逐步
介绍。
其它类型的模块
通过向其代码模块添加代码的方式可以给窗体类添加属性、方法和事件。还可以
用同样方法向类模块添加属性、方法和事件。对于VisualBasic专业版或企业
版,该方法还可添加到UserControl和UserDocument代码模块。
当读到“向类中添加属性和方法”及“向类中添加事件”这些节时,应记住文中
所描述的对窗体类所做的每一件事同样适用于类模块。
详细资料什么是类模块?在“类模块循序渐进”中介绍了如何定义类并列举了
通过类创建的对象的存活期。
类模块的循序渐进
本示例演示了如何用类模块定义类(然后可以用它创建对象)。还将展示如何为
新的类创建属性和方法并演示对象是如何创建和撤消的。
打开一个新的“标准EXE”工程,在“工程”菜单中选中“添加类模块”插入一
个类模块。在窗体上画四个按钮。下表列出了本示例中要设置的对象属性值。
对象属性设置值
Class类模块NameThing
Command1Caption显示该Thing
Command2Caption颠倒该Thing的名称
Command3Caption创建新的Thing
Command4Caption临时的Thing
注意类模块保存在扩展名为.cis的文件中。
添加下列代码到类模块的声明段:
OptionExplicit
PublicNameAsString
PrivatpindtmCrpAtprlAsDAto
变量Name将成为Thing对象的属性,因为它声明为Publico
注意不要把这个Name属性和上表设置的类模块的Name属性混淆(类模块的
Name属性为Thing类提供了名称)。为什么要给Thing类命名呢?最好应该
反过来问,为什么不?应该给Thing类一个名称因为事物总是有名称的!应该
知道VisualBasic使用属性和方法的名称并没有什么特殊点。可以为自己不同
的类使用相同的属性和方法名。
变量mdtmCreated是私有数据成员,用于存储只读的Created属性的值。
Created属性返回Thing对象产生的日期和时间。为了实现Created属性,将
以下PropertyGet代码添加到类模块的声明部分:
PropertyGetCreated()AsDate
Created=mdtmCreated
EndProperty
注意如果通过“工具”菜单下的“添加过程”对话框添加属性过程,应确认删
除了PropertyLet声明,它是通过本对话框自动添加的。PropertyLet只用
于读写属性,参见“运用属性过程”部分。
Thing对象有一个方法ReverseName,用于颠倒Name属性的字母顺序。它不返
回值,因此是一个Sub过程。向类模块添加以下Sub过程。
PublicSubRevcrseNameO
DimintCtAsInteger
DimstrNewAsString
ForintCt=1ToLen(Name)
strNew=Mid$[Name,intCt,1)&strNew
Next
Name=strNew
EndSub
类模块有两个事件:Initialize和Terminate。从类模块的“对象”下拉列表
中,选择“类”。下拉出的“过程”列表将显示事件。将以下代码放到事件过程
中:
PrivateSubClass_lnitialize()
’设置对象创建的E期/时间,
由只读的Created属性返回。
mdtmCreated=Now
'显示对象属性。
MsgBox"Name:"&Name&vbCrLf&"Created:
&Created,,〃ThngInitialize”
EndSub
PrivateSubClass_Terminate()
'显示对象属性。
MsgBox"Name:〃&Name&vbCrLf&"Created:
&Created,,“ThingTerminate”
EndSub
一
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 学校网络安全管理制度
- 确认合同付款条款确认函2026年4篇范本
- 2026年药理学与药物治疗考试试卷及答案
- 2026年中考政治练习题详解及答案
- 2026年敦煌色彩考试题及答案
- 行政执法人员综合法律知识考试试题(单项选择题)及答案
- 2026年内蒙古自治区辅警招聘考试题(含答案)
- 2026年咨询工程师(经济政策)题库及参考答案(完整版)
- 2026年广东辅警笔试及答案
- 2026年【煤炭生产经营单位(安全生产管理人员)】考试及答案
- 舆情法制培训课件
- 额敏县生活垃圾热解处理项目环评报告
- 借车试乘试驾协议书
- JJF(新) 139-2024 锅炉散热损失测试规范
- DB33T 1368-2024医院“一站式”综合服务中心建设与服务规范
- (医学书籍)张元素医学全书
- JJF 2154-2024亚低温治疗仪校准规范
- DB14-T 3149-2024 公路机电工程施工监理指南
- 《网络综合布线系统工程技术实训教程》(第5版)练习题汇 王公儒 1-15
- CJ/T 123-2016 给水用钢骨架聚乙烯塑料复合管
- (高清版)JTGT D81-2017 公路交通安全设施设计细则
评论
0/150
提交评论