Excel精英培训网

 找回密码
 注册
数据透视表40+个常用小技巧,让你一次学会!
查看: 44092|回复: 44

[分享] VBA模块的浅显理解

  [复制链接]
发表于 2011-3-31 02:16 | 显示全部楼层 |阅读模式
本帖最后由 wbzxz 于 2011-4-6 10:16 编辑

引   言

这些天来我一直在这个问题上纠结,因为我虽然断断续续的学了近1年的VBA,但是我却很糊涂,也很肤浅(当然和我没有用心学有关,嘿嘿)。可能是因为最近对类模块问题的思考,渐渐的把我引导到这个问题上来,到底是什么问题呢,请看下图:


image001.png

这是我们最熟悉VBE编辑器中的工程资源管理器。
我想问一个问题,这些是什么?当想到这个问题的时候,我觉得自己很可笑,因为图上写得很清楚,他们分别是Microsoft Excel对象,窗体,模块,类模块;但同时我又很糊涂,Sheet1不就是工作表对象吗?怎么还能在里面写代码呢?Range(“A1”)也是对象啊,怎么不能写代码呢?模块1也能写代码啊,模块1是不是对象啊?诸如此类的问题,把我搞的焦头烂额,完全可以说是一团浆糊,我突然感觉到自己对VBA那么陌生,因为我没有搞清楚这些基础问题,但这些基础问题好像微软没有给出我们系统的答案,我通过请教老师,翻阅资料,算是有了一点小小的理解,在这里和大家分享一下。

在此衷心感谢论坛的兰版、amule,吕布,HYY514等老师帮助,让我能从浆糊里面钻出来。

(一)什么是模块,VBA都包含什么模块呢?

首先我们来看微软VBA帮助中的三个定义:

模块:一组声明集合,其后为过程
声明:不可执行的代码,它命名一常数、变量或过程,并且指定其特性,比如数据类型。对于DLL procedures,声明指定名称、库和参数。
过程:命名的语句序列,可作为单元来执行。例如,FunctionPropertySub 都是过程类型。总是在模块级别定义过程的名称,所有可执行的代码必须包含在过程内,一过程不能套在其它过程中。

通过这三个定义我们了解到了什么信息,我们平常写的代码是什么东西,对,就是声明和过程,也就是在Sheet1Sheet2Sheet3ThisWorkbookUserForm1,模块1,类1这些东西里面编写的代码,所以我们可以得出结论,Sheet1Sheet2Sheet3ThisWorkbookUserForm1,模块1,类1都是模块。

这些虽然都叫做模块,但是却有所不同,其实微软是这样分类的:(微软这样分类是有根据的,后面我们会找到依据的)

文档模块:Sheet1Sheet2Sheet3ThisWorkbook
窗体模块:UserForm1
标准模块模块1
类模块:1

写到这里,有人可能会问,sheet1,sheet2这些本身就是微软为我们提供的内置对象,怎么能说是模块呢?诚然,在我们编写代码的过程中,它们确实是不同的对象。但是,由于微软单独把这些东西提取了出来,允许我们编写代码与这些对象进行关联,所以他们就具有了不同的意义,可以看作是微软自定义并已经嵌入的模块。由于我们能在他们内部编写并储存代码,所以,在这里,你就不要像看待range,cell等对象那样看待他们,而是要做为模块来看待他们。(这种思路的转变很重要,他们在这里我们是当作模块看待,而不是我们常用的对象)。

其实,作为VBA语言,来源于VB,所以他继承了VB语言的大部分功能,只不过微软单独为VBA提供了Excel对象(或者Word对象,PPt对象等等)。因为在VB中本身就提供了三种类型的模块:窗体模块、标准模块和类模块。所以VBA中就有了这三种模块。为了能够对Excel对象进行操作,微软又为我们提供了文档模块,而且是直接嵌入进来的(Sheet1,Sheet2,ThisWorkbook这些文档模块不需要我们插入,只要存在这个对象,就有这个文档模块)。所以,也就解释了,VBA为什么会有这四种模块。

我们通过上面的分析了解到了VBA的模块分为这四种,从什么地方可以看出微软是这样分类的呢,他们到底是不是对象(请一定和Excel模型中的Sheet1,Sheet2对象的概念分开,记住,在这里,他们已经是模块啦),他们到底是什么对象呢,大家请往下看。




评分

参与人数 8 +52 收起 理由
1091126096 + 15 赞一个!
zitongye2384 + 3
exc9211025 + 1 很给力!
轩辕轼轲 -18
兰色幻想 + 20 很不错,字母加油~~~

查看全部评分

 楼主| 发表于 2011-3-31 02:27 | 显示全部楼层
本帖最后由 wbzxz 于 2011-4-1 11:25 编辑


(二)模块属于什么对象?微软是如何来区分他的呢?
还是借用这个图
image007.png

由上图我们看出Microsoft Excel对象(文档模块),窗体(窗体模块),模块(标准模块),类模块这些模块都在什么下边呢,对,都在在VBAProject的下面

VBAProject是什么呢,就是我们平常说得工程,实际上他是VBAProject对象,他下面的这些Microsoft Excel对象(文档模块),窗体(窗体模块),模块(标准模块),类模块也都是对象,是什么对象呢,VBComponent对象。现在可以告诉你,这些模块就是对象,是叫做VBComponent的对象。

为了说明这个问题,需要引入一个概念,VBA扩展模型(VBA Extensibility Model,他具有对VBA工程和模块进行操作的功能:
1)用代码添加和删除VBA模块(而不是手动插入和删除);
2)用代码去创建代码(说起来有点绕,应该是用代码建立个模块,然后用代码在模块里面写代码)
3)创建用户窗体
VBA扩展模型能实现的功能非常多,我也说不了太清楚,毕竟我也是刚接触,呵呵。

VBA扩展模型的简单层次结构是这样(只为说明问题,没有全部列出来):
VBE
    VBProject
       VBComponent   
         CodeModule   
         Designer   
         Property
      Reference  
   Window  
   CommandBar

正如下图看到的,其实VBProject对象就是我们在工程资环管理器经常看到的,下面的Sheet1Sheet2Sheet3ThisWorkbookUserForm1,模块1,类1就是VBComponent对象。在这里我们得出了一个结论:文档模块,标准模块,类模块,窗体模块是对象,一种叫做VBComponent对象



VBComponent对象有个type属性,清楚的告诉了我们Sheet1Sheet2Sheet3ThisWorkbookUserForm1,模块1,类1分别属于什么模块,也就是上面所说的,微软是怎么对这些模块进行分类的呢,也就是type属性来告诉了我们这个问题。

我们用以下代码来展示这些模块都属于哪些类型。

image009.png
  1. Sub test()

  2.   Dim VBComps As VBComponents '定义VBComponents类的对象变量
  3.   Dim VBComp As VBComponent '定义VBComponent类的对象变量
  4.   
  5.   '这里我们借用了Thisworkbook这个对象来说明
  6.   Set VBComps = ThisWorkbook.VBProject.VBComponents '将对象的引用赋值给对象变量
  7.   
  8.   '利用循环来获取工程内每个组件的名称和类型
  9.   For Each VBComp In VBComps
  10.     MsgBox "组件名称:" & VBComp.name & "  组件常量" & VBComp.Type
  11.   Next
  12.   
  13. End Sub
复制代码
通过代码的运行,
我们发现

Sheet1Sheet2Sheet3Thisworkbook是一种类型,部件常数的值是100
模块1是一种类型,部件常数的值是1
1是一种类型,部件常数的值是2
UserForm1是一种类型,部件常数的值是3

下图是组件常数每个值的意义

QQ截图未命名.jpg
Vbext_ct_Document(常数)  100(值)  文档模块(描述)

通过上面的叙述,我不知道是否说清楚了这个问题,总结起来只是一句话:

文档模块,标准模块,类模块,窗体模块是对象,并且都是一个叫做VBComponent对象,根据VBComponent属性"type"(类型)的不同,微软把他们分为了4类:Vbext_ct_StdModule ,Vbext_ct_ClassModule, Vbext_ct_MSForm, Vbext_ct_Document.



回复

使用道具 举报

 楼主| 发表于 2011-3-31 02:27 | 显示全部楼层
本帖最后由 wbzxz 于 2011-4-1 11:27 编辑

(三)不同模块的介绍和模块之间的区别


上面我们大致搞清楚了这些模块的身份,下面我们来讨论一下模块本身吧。

以下是我应用了一篇叫做“vb中 窗体模块,类模块,标准模块的区别”文章的内容,原文章链接见这里
http://ykkykkl.blog.163.com/blog/static/718942282010717104046309/

VB的代码存储在模块中。在VB中提供了三种类型的模块:窗体模块、标准模块和类模块。
简单的应用程序可以只有一个窗体,所用的程序都驻留在窗体模块中,而当应用程序庞大复杂时,就要另外附加窗体。最终可能有几个窗体中有一些共同都要执行的代码,为了在两个窗体中不产生重复代码,可创建一个独立的模块,用它实现代码公用。该独立模块即是标准模块。此外还可以建立包含共享代码与数据的类模块。


1.窗体模块
由于VB是面向对象的应用程序开发工具,所以应用程序的代码结构就是该程序在屏幕上表示的对应模型。根据定交,对象包含数据和代码。应用程序中的每个窗体都有一个相对应的窗体模块(文件扩展名为.frm)
窗体模块是VB应用程序的基础。窗体模块可以包含处理事件的过程、通用过程以及变量、常数、自定义类型和外部过程的窗体级声明。写入窗体模块的代码是该窗体所属的具体应用程序专用的;也可以引用该程序内的其它窗体和对象
每个窗体模块都包含事件过程,在事件过程中有为响应该事件而执行的程序段。窗体可包含控件。在窗体模块中,对窗体上的每个控件都有一个对应的事件过程集。除了事件过程,窗体模块还可包含通用过程,它对来自该窗体中任何事件过程的调用都作出响应。


2.标准模块
标准模块是程序中的一个独立容器,包含全局变量、Function(函数)过程和Sub过程(子过程)。
可将那些与特定窗体或控件无关的代码放入标准模块中。标准模块中包含应用程序内的允许其它模块访问的过程和声明。它们可以包含变量、常数、类型、外部过程和全局声明或模块级声明。


3.类模块
在VB中类模块是面向对象编程的基础。可以在类模块中编写代码建立新对象。这些新对象可以包含自定义的属性和方法。实际上,窗体正是这样一种类模块,在其上可安放控件,可显示窗体窗口。
用类模块创建对象,这些对象可被应用程序内的过程调用。标准模块只包含代码,而类模块包含代码又包含数据,可视为没有物理表示的控件。


上面写得很清楚,下面我只写一些个人的看法:

我个人认为,首先我们要区分的是把标准模块文档模块、窗体模块,类模块区分开。

为什么我要这么说呢,其实微软本身也就是这样区分的,在vba帮助中有这样一个概念:

对象模块包含对象专用代码的模块,例如,类模块、窗体模块和文档模块。对象模块包含相关联对象之后的代码;对象模块的规则与标准模块不同。

从上面概念我们可以看出,标准模块和文档模块、窗体模块是属于对象模块的,可以作为一类,标准模块则是不同的,属于另外一类。

我个人认为标准模块和对象模块的区别主要有两点:
1. 首先,标准模块是不支持事件,对象模块都支持事件过程。
标准模块本身是没有事件过程的,这也就是说,你想写事件过程,绝对不要写到标准模块中去,当然你也写不进去。
2.标准模块是一个独立容器,标准模块中的全局变量、Function(函数)过程和Sub过程(子过程)是不与对象模块相关联的。
同一个工程中的对象模块可以共享和使用标准模块中的全局变量和过程。但是对象模块的变量和过程,却是该对象模块专属的。如果想调用的话,必须以对象的方式访问。


这也就告诉我们一个原则。通常我们在写VBA代码的时候,应该把公用的变量和过程写到标准模块中来,和对象模块相关的变量和过程写到相应的对象模块中去,这样才不容易出现问题。(我编写的VBA代码太少,反正这方面我是有些稀里糊涂的,写代码的时候,不太区分标准模块里还是对象模块中的,看来我以后要改正的。)



回复

使用道具 举报

 楼主| 发表于 2011-3-31 02:28 | 显示全部楼层
本帖最后由 wbzxz 于 2011-4-1 11:28 编辑

(四)有关文档模块,窗体模块,和类模块的一些猜想

接着,我想单独把文档模块,窗体模块,和类模块单独再说两句。

我在思考和实践的过程中发现,窗体模块和文档模块,完全可以像类模块那样定义属性,方法和事件(这个大家可以自己试试,代码太繁琐,我就不贴啦),并且可以在其他模块中调用,于是我猜想窗体模块和文档模块其实也是一种类模块,不过是一种特殊的类模块而已。

通过对象浏览器的截图,如下图所示

image007.jpg

image008.jpg


image009.jpg


image010.jpg



通过上图我们看出
Sheet1,Sheet2,Sheet3,ThisWorkbook属于Class
UserForm1,类1属于Private Class
应该说文档模块和窗体模块确实都是一种特殊类模块,或者说具有类模块的部分功能(后来这种思想也得到了HYY514老师的证实),所以他们可以定义属性、方法和事件,并且在其他模块中调用。

但是同标准类模块相比,窗体模块和文档模块不能像类模块那样被实例化成新的对象,他们本身已经是实例化的对象。
文档模块可以看做是微软自定义并已经嵌入的类模块,窗体模块是我们手动插入的模块(但他是一个实例化的对象)。

所以他们虽然可以定义属性,方法和事件,但也仅仅限于对象本身而已,并不能实例化为新的对象(如Sheet1模块定义的属性、方法,我们也只能对Sheet1调用的时候才能使用,不能像标准类模块一样,再创建一个Sheet1对象),这也就是文档模块、窗体模块和标准类模块最大的区别吧。

由于知识所限,我现在所能总结的也只有这些,希望有机会能够继续和大家分享。以上叙述中必然有不对,不合理与不准确之处,请大家积极的给我指出来,也希望大家积极的和我讨论,能够把这些概念搞的更加清晰,以利于大家对VBA的学习。



评分

参与人数 1 +1 收起 理由
苗凱 + 1 很細緻,師道存矣

查看全部评分

回复

使用道具 举报

 楼主| 发表于 2011-3-31 02:36 | 显示全部楼层
本帖最后由 wbzxz 于 2011-4-1 01:50 编辑

暂时不待续啦,先告一段落,呵呵。
回复

使用道具 举报

发表于 2011-3-31 08:44 | 显示全部楼层
学习学习,待续
回复

使用道具 举报

 楼主| 发表于 2011-4-1 01:57 | 显示全部楼层
请大家为我指出错误,欢迎大家的交流与讨论。
回复

使用道具 举报

发表于 2011-4-1 10:39 | 显示全部楼层
谢谢分享
回复

使用道具 举报

发表于 2011-4-2 14:16 | 显示全部楼层
关于类,在C++、JAVA中楼主会有更深的体会。
回复

使用道具 举报

 楼主| 发表于 2011-4-2 14:22 | 显示全部楼层
yuhe0008 发表于 2011-4-2 14:16
关于类,在C++、JAVA中楼主会有更深的体会。

谢谢yuhe0008老师,C++和Java我是一窍不通,为了搞懂vba而学Java和C++,说真的,怕学不会啊。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|Excel精英培训 ( 豫ICP备11015029号 )

GMT+8, 2024-4-25 06:35 , Processed in 0.352837 second(s), 8 queries , Gzip On, Yac On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表