本帖最后由 hyefeifei 于 2013-10-18 21:14 编辑
久在论坛,没啥贡献,前几日观字典与集合一文,忽受启发,把与类相关的知识做成一文件,供欲 了解类的朋友参考。
还有许多内容有空再继续增加。
类-字典-集合-接口.rar
(72.12 KB, 下载次数: 1045)
其实就是想聊一下类模块,及与类模块相关的字典-数组-集合-接口-窗体方 面的知识,有兴趣者可以一观。 因没有事先组织,加之水平有限,又基本是随想随发,错漏含混不准确之处 必不可免,希望能引发大家的指正和讨论。 一、方法问题: 古人有云,工欲善其事,必先利其器。器不利,事善难矣,学任何一门知识, 你不可能记住全部,或者哪怕大部,所以 有几本好的参考书随时检阅,是必须的。这里推荐几本VBA方面的书,这 几部书在后面的贴子里都会提供电子版下载地址(急的话百度一下,都可得到)。 第一本是办公宝典:Excel 2003/2002/2000 VBA大全(日人所著,浅显 易于查阅),第二部书为:Excel 专业开发(很有深度的一本书,老美所著),第 三部书为:VBA 高级开发指南(老美所著,国人所写的书,为什么就没有如此 有深度的呢?),这本书很老了,作者出了新版,不过没译过来。第四部书为: Excel2007 VBA参考大全(老美所著)。 本贴所谈及的知识,大部即来自第二部,第三部书相关内容,如果你下载了 这两部,且弄通了其中关于类的内容,则此刻即是离开的时候了。 没有离开的列位,容我再罗嗦几句,五柳先生说自己:爱读书,不求甚解, 后人大多只看到了不求甚解四字为自己囫囵吞枣式的读书开脱,但先生随后又有 言:每有会意,欣然忘食,会意二字,其实就是理解到了精髓,就是得到了甚解, 所以读书,尤其是读数理化计之类的书,应尽量求甚解,但如果不是为应付考试, 读书可以不必求全解,全解谁有那个精力求?有了我推荐的那四本书,加之有了 本坛,又有通晓万事的度娘,求全解确实不必了。 闲言少绪,步入正题 二、什么是类? 首先啥是对象?对象就是世界中每一个具体的东西,比如说我邻居家那条叫 小波的狗,经常招摇地停在车库门前那辆大家称之为大黄峰的跑车,这两者都是 对象。 那么,现在我们要做的是找一下两者共同具有的属性呢?随便找一下:a. 它们都有个名称,b.他们都有重量,c.他们都有不同的叫声,就这三条吧,如果 我们把(名称,重量,叫声)聚合 在一起,这就形成一个类了,我可以把这个 类起个名:"小区会叫物",名字当然可以随便起,这里,小波,大黄峰这两个 对象,就是"小区会叫物"这个类的实例化,或者说类"小区会叫物"实例化后 产生两个对象小波,大黄峰。现在类"小区会叫物"有三个属性了,但小波,大 黄峰还有共同点,比如都会跑,再比如都会发出叫声(注意,属性里的"叫声"是 个名词,"发出叫声"是个动词 ),跑 和 叫,这是两者都有的动作,那么,我 们可以把"跑"和"叫",也加入"小区会叫物"类中,现在类"小区会叫物"是 五个元素聚合在一起(名称,重量,叫声,跑,叫),前三个叫属性,后两个元 素我不说大家也知道,叫方法。 现在,假如说我们是为研究小区噪音而建的这个类,那么重量这个属性,虽 然为小波,大黄峰共有,但与噪音无关,我们不感兴趣,可以从类中去除,最终, 类"小区会叫物"由两个属性,两个方法聚合而成(名称,叫声,跑,叫),其 实,小区著名的悍妇甲,也可以归为这个类的实例化对象。 总结一下,类即是A、B、C、D等不同对象中我们感兴趣的共同属性和方 法的聚合。而对象,就是类的实例化,或者说对象就是类的实例。实例和对象是 一回事。 三、建立类模块 插入类模块不用说了吧,这里建议把类模块起个有意义的英文名字,比如 student,member等,这里,我们使用Excel 专业开发一书中的例子,建一个 类模块,用于分析单元格区域中每个单元格的属性(即分析单元格中的值,为文 本型,还是数值型,还是日期型,还是空值等),我们把类模块命名为rngFormat, 我们已经知道,类是由属性方法聚合而成,那么现在就为类rngFormat添加第 一个属性,因为我们的目的是要知道某单元格值的类型,那我就先给类加一个"类 型"属性,当然属性的名称可以为中文,但在vba中,一定要把所有的变量, 方法,属性等用个有意义的英文单词或词组表示,英文不灵光可以查下什么什么 词霸,懒得查最不济也要用拼音。 好了,"类型"这个属性,我用DataType表示,在类rngFormat模块中, 输入如下语句: Private m_oCell as Range Private Property Set DataType(rng As Range) Set m_oCell = rng End Property 这是什么意思呢?这个语句就是给属性赋值(不那么确切地说),它其实就 是把你在标准模块中给属性赋的值,通过rng参数,传递给模块内的变量 m_oCell,比如当你在标准模块中输入 Set xxx.Datatype=range("a1")时, m_oCell就会得到A1。注意:这里用了Set DataType,set oRng=rng,大家想 必明白,如果Rng参数不是对象类型的话,set 要变成let,而第二个Let可省 略。 再说一句题外的,各位在使用vba时,一定要打开强制变量声明这个选项, 在所有过程模块中显式声明变量,原因就不题了。所以我们在模块顶部声明了私 有变量m_oCell。 当类得到具体的单元格后,要经过一番分析得出单元格的类型,然后输出, 要如何作呢? 请在类rngFormat模块中输入如下代码: Public Property Get DataType() As String If IsEmpty(m_oCell) Then DataType = "空值" ElseIf m_oCell.HasFormula Then DataType = "公式" ElseIf IsNumeric(m_oCell) Then DataType = "数字" ElseIf IsDate(m_oCell) Then DataType = "日期" Else DataType = "文本" End If End Property 一般来说, Private Property Set(Let) xxx(aaa As bbb) End Property Public Property Get xxx() As ccc End Property 总是成对出现,前者把一个值(或对象)传递给模块内的变量,后者,通过 分析取得该属性的具体值。 现在转到标准模块,在标准模块中,建一程序: Sub test() Dim rng As Range, i As Long Dim rF As rngFormat Set rF = New rngFormat For Each rng In Range("a1:a5") rng.Value = Array(#6/1/1966#, "abc", "=3", "100", "")(i) Set rF.DataType = rng rng.Offset(, 1) = rF.DataType i = i + 1 Next End Sub Test程序只解释两句: 当程序运行到:Dim rF as rngFormat这一句时,rf 成为一个类,当程序 运行到Set rF =New rngFormat这一句时,rF被实例化为一个对象。经常有人 把这两句并成一句:Dim rf as new rngFormat,这样当然也可以,但这两者的 区别何在呢? 类模块比标准模块多了两个事件Class_Initialize()事件和 Class_Terminate()事件,当我们把两句并成一句声明时,当程序运行到第一次 引用类时,触发Class_Initialize()事件,对于Test程序,运行到这一句:Set rF.DataType = rng 时,第一次引用类模块,触发Class_Initialize()事件。而当 我分两句时,当程序运行到set rf=new rngFormat时,触发Class_Initialize() 事件,即此事件在类实例化为对象时触发。 对于类来说,建议分成两句代码。 说到这里,希望初学者已经把Excel打开,并把相关代码复制过去,并且运 行test程序已经获得了正确的结果,请一定做到这一点再往下看。 我们返回Excel类模块查看其中的代码,里面只有一个属性:DataType。不 知你是否觉得有点怪,Public Property Set DataType(rng As Range)这一句, DataType是我们定义的数据类型属性,而它却得到一个单元格对象(rng),其 实,这一句主要作用是把rng这个参数,传递到类模块里面,取什么名字并不 要紧,这里我们给它换个名字,让它名副其实一些,我们把.DataType改成Cell, 这样,代码变为: Public Property Set Cell(rng As Range) Set m_oCell = rng End Property 在标准模块中这一句:Set rF.DataType = rng,也要改为:set rF.Cell=rng 这时,我们再看类模块,原来只有一个DataType属性,现在变成有两个属性了, 一个是Cell属性,一个是DataType属性。 我们看Cell属性,只有set cell(xx),没有get cell与它对应,那它就是一个只写 属性,而datatype属性,只有一句 get datatype,没有set datatype与它相 对,那它就是一个只读属性,对于datatype,因为它的值是通过传进来的变量 算出来的,所以它只能是只读的,而对于cell属性,我们则可以读取它的值,如 何做到呢?不是说了吗,set(Let) 与Get 大多是成对出现的,我们只须在类模 块中加入下面代码,即可让cell属性,变成可读写属性: Public Property Get Cell() Set Cell = m_oCell End Property Public Property Set Cell(rng As Range) 把rng参数传给了内部的变量 m_oCell,所以在get语句中,我们直接再把m_oCell赋给Cell即可。 让我们在test模块做些改变,测试一下效果,在rng.Offset(, 1) = rF.DataType 这一行后,加入这一句: rng.Offset(, 2) = rF.Cell.Address 此时再运行test,即可看到效果。 但是,这里还有个与效率相关的问题,你仔细看类模块的get datatype属 性,会发现其中包含了好几层if判断,每一次引用datatype属性时,都要决断 一遍,如果我们要频繁引用属性,那就会频繁重复做if判断,那么怎么解决这 个问题呢?那就是引入方法,待续......
|