1.1.2 在正确的位置编写代码
1.工程与模块
在实际工作中,我们经常会在一个 Office 文件中写多个 VBA 程序,分别完成不同的任务。比如,在一个存放工资表的Excel工作簿文件中,就可能需要编写“计算所得税”“生成统计表”“打印工资条”等不同用途的程序。随着时间的变化,我们会在这个工作簿中不断编写更多的VBA程序,逐渐使所有工资管理工作都做到自动化处理。这样一个文件中保存的 VBA 程序可能多达几十个甚至上百个,翻阅起来将十分吃力。
怎样能够把这些程序保存得井井有条,便于查阅和修改呢?VBA 引入了“工程(Project)”和“模块(Module)”两个概念来对不同类型和用途的代码进行系统化管理。一个VBA工程,就是针对某个Office文件编写,并且保存在这个Office文件中的所有VBA程序。为了让这些程序被保管得有序,每个工程会被进一步划分为多个“模块”,分别存放不同类型或功能的VBA程序。
这个结构与Windows系统的文件管理模式十分相似:一个工程就像一个硬盘分区(如“D:”),一个模块则是该分区下的一个文件夹(如“D:\Print\”),每个VBA程序则如同一个文件,需要根据其特点存放到某个文件夹中。VBE的“工程”窗口,就像Windows系统的“我的电脑”窗口专门用来查看和管理“文件”与“文件夹”,也就是模块和 VBA 程序。VBA 工程结构与 Windows系统文件结构的对比如图1.4所示。
图1.4 VBA工程结构与Windows系统文件结构的对比
根据语法特点与运行方式,VBA 程序可以分为四种类型。相应地,VBA 工程中也包含四种类型的模块,分别存放每种类型的程序。
2.事件程序与Office对象模块
事件程序是一种能够在用户执行某个Office操作时自动运行的程序。当用户在表示“年龄”的单元格中输入一个数字时,就可以自动运行一个事件程序,判断该数字是否在规定范围内。
在 Excel 中,用户的日常操作主要针对“工作表”和“工作簿”两种对象,比如在工作表中选中一个单元格,或者将工作簿保存并关闭等。所以,Excel的VBA工程为每个工作表和工作簿都安排了一个单独的模块,用于存放针对该工作表或工作簿的事件程序。假如一个 Excel 文件中包含两张工作表,那么我们就能够在VBE的工程窗口中看到两个工作表模块和一个工作簿模块。用鼠标在工程窗口中双击上述任何一个模块,就可以在右侧代码窗口中看到这个模块中的所有程序,并且可以添加新的程序。Excel对象模块(事件程序)示例如图1.5所示。
图1.5 Excel对象模块(事件程序)示例
如果是在Word或PowerPoint等Office软件中编写VBA程序,那么可以在它们的VBE中看到对象模块,只不过它们被统称为“Word对象”“PowerPoint对象”等,里面的具体模块则是“文档”“幻灯片”等对应元素。关于事件程序的具体内容和开发方法,本书后面将会详细介绍。
3.标准程序与标准模块
事件程序必须与某个特定的对象(如第二张工作表)和某种特定的操作(如单击单元格)捆绑在一起,只有当用户在该对象中执行这个操作时才会运行。而我们在实际工作中编写的大多数VBA程序,却是希望用户可以随时随地运行,不需要和任何特定对象或操作发生关联。这种“更为常见”的程序,就称为“标准程序”,相应的代码需要保存在“标准模块”中。
与事件模块不同,VBA工程中没有事先准备好标准模块,需要我们在工程窗口手工创建。在工程窗口的任意空白位置单击鼠标右键,在弹出的菜单中选择“插入”→“模块”命令,就可以向这个工作簿的工程中添加一个标准模块,如图1.6所示。请注意,由于标准模块非常常用,在工程窗口中直接将“标准模块”简称为“模块”,所以读者在阅读本章时不要将其与广义的“模块”一词(涵盖事件模块、标准模块、窗体、类定义等)混淆。
我们可以反复执行上面的“插入”操作,在一个VBA工程中添加多个标准模块,把将要编写的众多VBA程序按照业务功能等方式分别保存到不同的模块中,便于查阅和管理。在工程窗口中双击任何一个模块,右侧的代码窗口都会切换到该模块,显示这个模块中的所有VBA代码。
日常编写的VBA程序大多属于标准程序,所以标准模块的使用也将贯穿本书始终。
图1.6 在VBA工程中插入标准模块
4.图形界面程序与窗体模块
为了让程序更加友好,方便用户操作,我们还会经常编写一些具有图形用户界面(GUI)的程序。因为开发这些程序时不仅需要编写代码,而且需要使用VBE提供的专门绘制窗体、按钮等元素的绘图工具,所以这些VBA程序也被单独分为一类,需要保存到窗体类型的模块中。
与标准模块一样,VBA工程事先也没有提供任何窗体模块。我们可以在工程窗口的空白处单击鼠标右键,在弹出的菜单中选择“插入”→“用户窗体”命令,就可以在当前工程中插入一个窗体模块。当界面要求比较复杂,需要设计多个不同的窗体时,可以反复执行“插入”操作,创建多个窗体模块,每个模块能且只能保存一个窗体。双击一个窗体模块,就可以在右侧代码窗口中看到“窗体设计器”,也就是绘制图形界面的工具。双击正在其中绘制的用户窗体,代码窗口就切换为代码模式,用于显示和编辑这个窗体对应的程序代码。窗体模块与窗体设计器示例如图1.7所示。
对于用户窗体和图形界面设计的详细内容,本书后面有专门章节进行讲述。
图1.7 窗体模块与窗体设计器示例
5.类定义程序与类模块
VBA 的高级用户有时还会用到定义“类”的程序。“类”是“面向对象”这种程序设计思想中的一个基础概念,按照这种思想编写的代码,只需稍加修改就能够重新用于其他系统中,从而使开发者在设计新系统时不必重写功能相似的代码,减轻了工作压力。
与标准模块相似,开发类定义程序必须先在工程窗口中弹出“插入”菜单,然后插入一个类模块,双击类模块就可以在代码窗口中显示和编辑类定义程序。
对于VBA的初学者来说,类定义并不常用,所以本书将相关内容放在最后介绍。
以上就是 VBA 程序的四种类型,以及对应的四种存储模块。其中最常用的就是标准程序与标准模块,所以本书后面将主要基于这类程序讲解VBA语法知识。
需要特别说明的是,当一个工作簿中包含的 VBA 程序较多时,为使工程结构更加清晰,我们不仅会建立多个模块保存不同用途的程序,还会为这些模块重新命名,使其内容一目了然。为模块命名的方式很简单,只要在VBE中按“F4”键,或者在VBE的“视图”菜单中选中“属性窗口”选项,就可以在“工程”窗口的下方看到“属性”窗口。在“工程”窗口中选中一个模块,就可以在“属性”窗口中修改该模块的名称,如图1.8所示。注意,此操作仅适用于标准模块、窗体模块和类模块,Office对象模块的模块名称不允许被修改。
图1.8 修改模块的名称