集合类:VBA集合对象的安全包装
时间:2009-6-2 10:27:47 作者: 来源:
 
你迟早都要管理一组由vba类模块创建的自定义对象,vbacollection对象是实现这一目的的理想工具。我们在该杂志的premiere期刊中曾经介绍过collections,并且阐述了如何使用collection对象来存储其他对象。虽然该项技术十分有用,但它确实还存在一些局限。在本文中,我们讨论了这些局限,并向你展示如何通过使用(你猜是什么)类模块来克服这些局限。


collections中遇到的麻烦


collections对象中到底有什么问题呢?它似乎存储对象存储得非常好。事实上,它工作起来的确是太好了。collections对象得最大问题是它可以存储到任何数据类型得引用,例如integer,string,long,variant,等(见图1)。


当然,如果你能保证每个对象都具有相同得类型,并且具有相同得属性何方法的话,那么在collection中处理对象就变得异常简单。例如,作为本月范例excelvba项目的组成部分,我们创建一个自定义的file类来代表一个磁盘文件。这个file类有几个属性,其中包括path,size,和shortname。如果你创建了一个file对象的collection,那么你将希望这个collection中的每个对象都具有这些属性。你可以毫无异议地使用与下面类似的代码:


'printthesizeofthefirstfileinthecollection.
debug.printcolfiles.item(1).size


但是,如果colfilescollection中的第一个对象不是file,将会出现什么情况呢?如果它是一个form或control对象,又会怎样呢?如果它根本就不是一个对象呢?当然,当它试图执行该代码的时候,vba将生成运行时间错误。




图1(左)vbacollection对象可以容纳任何类型的对象



图2(右)创建一个collection类来防止不想要的对象进入集合


输入collection类


collection类可以充当collection对象的过滤器,限制你可以在里面存储的对象类型(如图2所示)。通过与你的应用程序中的collection类(二不是collection对象本身)的互相作用,你可以防止不想要的对象的进入。创建和使用collection类允许你扩展collection对象的属性和方法(后面我们将举例说明)。


为了说明collection类以及如何创建一个collection类,我们将使用带有通过扫描磁盘目录创建的文件集合的excel97项目。图3显示了一个表单,它用你选择了路径之后存储在自定义collection类中的文件信息使得列表框通俗化。


这个表单使用一个叫做files的collection类来通俗化列表框。在创建collection的时候,以向你的vba项目添加一个新的类模块作为开始,然后在这个新模块的声明段声明一个privatecollection对象。下面是来自files类模块的声明:


'collectionoffiles.
privatepcolfilesasnewcollection


为了将collection对象与外界"隔绝",并阻止程序的其他部分用无用的东西填充它,必须将collection对象声明为private。


复制所需要的方法


当然,一旦你已经将collection对象声明为private,那么对于任何过程都没有办法向其中添加项目或从中删除项目了。因而,下一步就是复制collection对象的标准方法了。尽管听起来象是做了大量额外的工作,实际上仍然在做我们前面所提及的"过滤"工作。


请记住,内建的collection对象具有add方法,该方法接受对象引用和独特的、包括文字与数字的标识符。如果你的应用程序正在直接使用collection对象,那么它将极有可能创建对象的一个新的实例,并将其添加到collection本身。


'createanewinstanceofanobject.
dimobjfileasnewfile
objfile.path="c:autoexec.bat"

'addtoacollectionobject.
colfiles.addobjfile,objfile.shortname

应用collection类,应用程序调用该类的add方法,传递任何必需的信息。请将先前的代码与files类的add方法做一比较:

withacollectionclass,theapplicationcallstheaddmethodoftheclass,passinganyrequiredinformation.contrastthepreviouscodewiththeaddmethodofthefilesclass:

publicfunctionadd(pathasstring)asfile

dimobjfileasfile

'createthenewfileobject.
setobjfile=newfile
objfile.path=path

'addittotheprivatecollection.
pcolfiles.addobjfile,objfile.shortname

'returnapointertothenewobject.
setadd=objfile

endfunction

在本例中,到collection的对象创建和添加发生在add方法内部;而类则保留了完整的控制。任何必需的信息(例如文件的路径)是作为参数向方法提供的。由应用程序调用将文件添加到collection的代码然后可以简化为:

'addafiletothecollection.
colfiles.add"c:autoexec.bat"
inadditiontotheaddmethod,thecollectionclassshouldalsoimplementtheitemandremovemethods,aswellasacountproperty:

publicfunctionitem(keyasvariant)asfile
'returnaniteminthecollection.
setitem=pcolfiles.item(key)
endfunction

publicsubremove(keyasvariant)
'removeanitemfromthecollection.
pcolfiles.removekey
endsub

propertygetcount()aslong
'returnthenumberofitems.
count=pcolfiles.count
endproperty

请注意,在这三种方法中,我们省略了错误处理--有些事情你是从来都不应该做的!至少应该包括一个错误处理器,通过使用err对象的raise方法来将错误传递、给调用过程。

图3这个表单通过显示文件信息来说明collection类

'privatevariabletostorepath.
privatepstrpathasstring

propertygetpath()asstring
'returnstoredpathvalue.
path=pstrpath
endproperty

propertyletpath(strpathasstring)

dimstrfileasstring

'clearthecollection.
setpcolfiles=newcollection

'makesurethere'sabackslash.
ifright(strpath,1)<>""then
strpath=strpath&""
endif

'getthefirstfile.
strfile=dir(strpath&"*.*",_
vbreadonlyorvbhiddenorvbarchiveorvbsystem)
dountillen(strfile)=0
'addittothecollection.
calladd(strpath&strfile)
'getthenextfile.
strfile=dir()
loop

'savethepath.
pstrpath=strpath

endproperty

图4向collection类添加path属性。将该属性和类设置为扫描目录并将所找到的每个文件添加到私有collection对象。

扩展collection类

现在,你可以通过声明files类的一个实例来使用它了,并为曾经由dir函数找到的每个文件反复调用该类的add方法。但这不是我们的例子要完成的工作。为什么不是呢?使用collection类的一个优点是你可以通过添加更多的属性和方法来扩展它的功能;不仅仅限于add,remove,item,和count。

在我们的files类的情形中,它难道不对在类本身,而不是使用该类的每个应用程序里面,放置扫描目录的代码做更多的检测吗?这是面向对象设计的一个指导原则:将代码放在最靠近需要它的地方。

为了阐述这个概念,我们向collection类添加了一个path属性。当你设置这个属性的时候,这个类将对目录进行扫描,并向collection对象添加它所找到的每个文件(见图4)。

当一个过程改变该类的path属性的时候,将触发propertylet过程。在我们的例子中,它发生在你从浏览器对话框选择了一个路径之后。这里是完成用文件列表填充collection任务的简单代码。

'reinitializethecollection.
setmobjfiles=newfiles

'setthepathproperty.
mobjfiles.path=strpath

一旦设置了path属性,files类就将通俗化它自己的collection,并且使它可以提供给应用程序。这已经是另一个例子了,在这个例子里面,过程的"guts"存在于类自己内部(你可以证明类已不再需要它的add和remove方法了。在有些应用程序中,可能确实是这样,但为了达到说明的目的,我们已经选择了留下它们作为该类的一部分)。

一些不利之处

使用vbacollection类的生活并不总是美酒和玫瑰。当你使用collection类代替collection对象时,必须放弃两样东西。第一样是collection对象的默认方法,item。默认的方法允许你从你的代码中省略单词"item"。例如,如下两条语句是一样的,都是假定colfiles引用一个collection对象。

debug.printcolfiles.item(1).size
debug.printcolfiles(1).size

除非你正在使用的是visualbasic5.0,否则没有办法为一个类指定默认的方法。因而,你必须总是显式调用item方法。

collection类的第二个主要的不足之处是不能创建列举函数。列举类就是可以使foreach循环工作的类。如果你想重复collection中的每一个项目,那么就必须用老式的方法来完成,也就是使用count属性和fornext循环。例如,下面的代码可以通俗化列表框:

'fillthelistboxwithinfo.
lstfiles.clear
forlngcount=1tomobjfiles.count
withmobjfiles.item(lngcount)
lstfiles.additem.shortname&_
space(12-len(.shortname))&_
vbtab&.attributestring&_
vbtab&.size
endwith
next

请注意该过程是如何使用计数器变量lngcount来完成从1到collection中项目数的循环的。with语句使用了item方法来引用collection中的每个对象。

请注意,visualbasic5.0用户可以通过创建列举函数来克服这一局限。在visualbasicbookonline中搜索关键字"enumeration"可以得到更为详细的信息。->


上一篇:
下一篇:
 
网页模板 网站模板 网站建设 网页设计 网页设计师兼职 自助建站 ...
网站魔坊,网页模板,网站模板,免费网页模板,在线模板设计,免费建站,门户网站搭建,建站,企业网站,奇思网络,奇思,智能建站,自助建站,拖动建站,网站建设,网页设计,在线设计模板
www.wzmof.com/ 47K 2009-5-21
 
商巢...
商巢是一个真实的商业交友社区、为用户提供交友、贸易、社区、建站等服务;临渊慕鱼,不如退而结网!商巢结网行动
www.ncooo.com/ 47K 2009-5-21
 
商巢创业 门户创业 商人网络家园 魔坊建站 商业交友
商巢下的门户,门户又一独立实体与商巢合作,由商巢负责技术的更新以及硬件的支持,门户负责自己领域的市场推广以及相应的售后服务即可。 打破以往门户需要源源不断的技术、硬件投入模式,盈利模式清晰 行业门户以及门户下企业网站由网站魔坊...
mhcy.ncooo.com/ 36K 2009-5-14
 
奇思网络技术 网站建设 深圳网站建设
中小外贸企业做电子商务,需要从两点技术突围 08-01 企业网站建设 提供网站策划、网站建设、数据库开发至网络营销全套解决方案。能针对客户所处行业,结合营销特征量身订做高质量网站建设方案。 网站推广 怎样使网站的投资得到回报?这需要经验...
www.qsnet.com.cn/ 48K 2009-4-2
 
深圳艺术网
深圳艺术网,中国艺术网,中国当代艺术网,广东当代艺术网,广东艺术网,南方当代艺术网,深圳美术网,深港美术网,深港艺术网,深港当代艺术网,杜应红,深圳当代艺术创作库,深圳创库,深圳美术,深圳艺术,深圳收藏,深圳艺术收藏,深圳音乐网,深圳舞蹈...
www.szarts.cn/ 119K 2009-6-9
 
网页设计也通过人脉赚钱-技术传播
 
网页设计114 -打造中国网页设计、网站建设技术信息学习、交流、互动平台
                         打造网页设计师兼职创业平台中心