第1章 VBA编程概述
本章主要介绍VBA的一些背景知识、宏的安全性设置、录制与使用宏、使用Excel VBA进行编程的界面工具VBE窗口的组成等内容,最后还介绍了开发Excel应用程序的一般流程。
1.1 VBA简介
本节对Excel VBA的发展历程进行了简要介绍,还介绍了使用Excel VBA的原因,以及Excel VBA所提供的主要功能。
1.1.1 VBA发展历程简述
VisiCalc是世界上最早出现的电子表格软件。虽然以现在的标准看,VisiCalc存在着很多不完善的地方,但是它为之后的电子表格软件的设计方向奠定了基础。在VisiCalc之后出现的是Lotus 1-2-3,它是当时非常成功的电子表格软件。Lotus 1-2-3中的宏直接输入到表格的单元格中,由于当时还不存在包含多个工作表的工作簿,因此宏的完整性及其功能很容易受到用户的破坏,进而导致频繁出错。
与VisiCalc类似的是Microsoft公司开发的Multiplan,该软件是Excel的前身,但其并未取得成功。1985年在Macintosh操作系统中第一次看到了Excel,它使用了图形化的界面。1987年Microsoft发布了适用于Windows操作系统的第一个Excel版本,版本号为Excel 2.0。随后Microsoft又发布了Excel 3.0、Excel 4.0和Excel 5.0,在Excel 4.0中提供了功能强大的XLM宏语言。XLM宏语言是由保存在工作表中的几百个函数调用组成的,这些函数提供了Excel的所有功能,并允许对Excel进行编程控制,但是增加了学习和使用的难度。
Microsoft在1993年发布的Excel 5.0中首次加入了VBA,随后其被陆续添加到Word、PowerPoint、Access等其他Office组件中。通过编写VBA代码,能够实现在不同的Office组件之间访问数据。Microsoft在后来发布的Excel版本中对VBA进行了不同程度的改进,比如增加了大量的事件,通过编写事件代码可以自动响应用户的操作。此外,还为VBA提供了一个扩展库,从而允许用户通过编程来自定义VBE环境(Visual Basic Editor,VBE)。
Excel 2007是Excel发展历程中一个具有重大意义的版本,它是自Excel 97以来发生最大变化的版本。由于Excel 2007使用了功能区界面代替早期Excel版本中的菜单栏和工具栏,因此通过编程定制Excel界面环境的方法也与以前大不相同。Excel 2016/2013/2010等后续版本与Excel 2007类似,虽然在功能区界面环境方面存在一些区别,但是没有本质上的改变。本书以Excel 2016为操作环境来讲解Excel VBA知识,但是书中内容同样适用于Excel 2016之前的Excel版本。
提示:“宏”通常指的是一组VBA代码。在Excel中将录制VBA代码的操作称为“录制宏”。本书会介绍很多VBA术语,也会使用“宏”这个术语作为表示任何VBA代码的一般方式。
1.1.2 VBA的应用场合
由于本书的主题是Excel VBA,因此本节介绍的VBA的应用场合主要是指在Excel环境下,但是列举的这些应用场合也同样适用于其他支持VBA的Office组件。虽然Excel已经提供了非常丰富的功能,以满足日常应用所需,但是仍然有很多原因需要使用VBA,下面列举了需要使用VBA的应用场合。
1.简化操作,批量完成任务
使用VBA或者说录制宏的一个原因是可以将多步操作简化为一步。例如,可能需要对单元格设置多种格式,包括字体、字号、字体颜色、数字格式等。常规方法是在操作界面中逐一找到设置项并依次设置这些格式,或者通过预先定制单元格样式,然后再一次性将样式应用到指定的单元格中。使用VBA则可以瞬间完成以上操作,并可重复使用,便捷高效。
对于需要输入复杂公式的情况,可以通过使用VBA编写自定义函数来简化公式的输入,即使对函数语法不熟悉的用户,也可以轻松使用自定义函数完成数据的计算任务。
2.轻松处理专业数据
很多普通用户可能很难使用Excel处理自己不擅长的专业领域中的数据。我们通过使用VBA预先编制数据处理和分析程序,或者更复杂的人事管理系统、财务管理系统等专业化程序,从而使非专业人员只需单击几下鼠标就可以轻松处理专业数据,而无须浪费时间学习相关专业知识。
3.扩展程序功能
虽然Excel自身已经提供了大量丰富的功能,但是永远也跟不上来自各方面的日新月异的使用需求。使用VBA可以根据应用需求编写量身定制的程序,从而完成Excel内置功能无法实现的特定任务。例如,当需要在Excel中操作Word文档或读取注册表的配置信息时,就必须借助VBA才能实现。
4.开发专业插件
使用VBA还可以开发专业插件。插件以文件的形式存在,可以被多个用户安装和使用,用于完成一个或多个功能。插件具有普适性,而不只是针对某个特定用户。由于需要考虑插件通用性的问题,因此开发插件比编写针对单一用户并完成简单功能的VBA程序要复杂得多。
1.1.3 VBA的特点
与其他编程语言不同,VBA代码可以通过录制的方式自动创建,这样对于不了解VBA编程知识的用户而言非常方便。然而凡事都有利弊,虽然可以通过录制的方式自动创建VBA代码,但是代码本身会包含冗余部分,影响运行的性能,而且兼容性较差,录制的VBA代码通常只能完成特定单元格区域中的一项特定任务。
VBA本身的语法规则通用于Excel、Word、PowerPoint、Access等多个Office组件,因此学习VBA语法投入少,回报高。一旦掌握了VBA的语法规则,就可以将其应用到所有支持VBA的Office组件中。但是如果希望在特定的Office组件中真正发挥VBA的作用,还需要掌握与该组件对应的对象模型。例如,如果希望在Excel中编写能完成Excel相关任务的VBA代码,则需要学习Excel对象模型。
相对于其他类型的编程语言而言,VBA更容易学习和掌握,而且开发效率较高。这是因为VBA中内置了大量的对象,用户在大多数情况下不需要额外创建新的对象,而是直接使用VBA提供的现有对象,并使用它们的属性和方法来完成各项任务。
1.2 Excel文件格式
微软从Excel 2007开始为Excel工作簿提供了新的文件格式,新格式的文件扩展名在Excel 2003文件格式扩展名的结尾多加了一个字母x或m,即.xlsx和.xlsm。新的文件格式是以工作簿中是否包含宏来作为划分标准的,以.xlsx格式保存的工作簿不能包含宏,而如果希望工作簿中包含宏,则必须将工作簿以.xlsm格式保存。当然,如果以早期Excel版本中的.xls格式保存工作簿,则就可以灵活选择是否包含宏。表1-1列出了Excel 2007/2010/2013/2016包含的主要文件类型及其扩展名。
表1-1 Excel文件类型及其扩展名
在Excel 2007或更高版本的Excel中打开由Excel 2003或更低版本的Excel创建的格式为.xls的工作簿时,将会自动进入兼容模式,并在Excel程序窗口的标题栏中显示文字“兼容模式”,如图1-1所示,此时无法使用Excel 2007或更高版本的Excel提供的新功能。
图1-1 在高版本Excel中打开.xls格式的工作簿会自动进入兼容模式
可以单击“文件”按钮,然后依次选择“信息”|“转换”命令,将.xls格式的工作簿转换为.xlsx格式。如果转换前的工作簿中包含VBA代码,那么转换后的工作簿的格式将会是.xlsm。
1.3 宏的安全性设置
为了可以正常运行Excel工作簿中的宏,或是出于安全性方面的原因而禁止运行工作簿中的宏,都应该了解和正确设置宏的安全性选项。本节将介绍Excel中关于允许或禁止运行宏方面的选项设置的方法。
1.3.1 临时允许或禁止运行宏
默认情况下,当打开包含宏的工作簿时,在功能区的下方会显示一条“宏已被禁用”的消息,其中还会包含一个“启用内容”按钮,如图1-2所示。如果确定工作簿中的宏是安全可靠的,可以单击该按钮以允许运行该工作簿中的宏。否则可以忽略该消息,这样就不能运行这个工作簿中的宏,但是可以查看和修改宏。
图1-2 打开包含宏的工作簿时显示的消息
1.3.2 允许运行特定文件夹中的宏
Excel允许用户将指定的文件夹设置为允许宏运行的文件夹,只要从这个文件夹中打开包含宏的工作簿,其中的宏就可以运行。在Excel中将这类文件夹称为“受信任位置”。Excel自身提供了一些默认的受信任位置,用户也可以向Excel中添加新的受信任位置,这样就可以将包含宏的工作簿集中保存在同一个文件夹中,便于使用和管理。
可以使用下面的方法打开用于设置受信任位置的对话框:
(1)单击“文件”按钮,然后选择“选项”,打开“Excel选项”对话框。
(2)在左侧选择“信任中心”,然后在右侧单击“信任中心设置”按钮,如图1-3所示。
图1-3 单击“信任中心设置”按钮
(3)打开“信任中心”对话框,在左侧选择“受信任位置”,右侧显示了Excel默认的受信任位置,以及用户添加的受信任位置,如图1-4所示。
对受信任位置主要可以进行以下3种操作。
1.添加新的受信任位置
除了Excel默认提供的受信任位置之外,用户还可以将自己创建的文件夹设置为受信任位置。在图1-4中单击“添加新位置”按钮,打开如图1-5所示的“Microsoft Office受信任位置”对话框,其中显示的默认路径是在打开该对话框之前,在受信任位置列表中选择的位置。
图1-4 Excel默认的受信任位置和用户添加的受信任位置
图1-5 添加新的信任位置
要添加新的位置,需要单击“浏览”按钮,然后选择所需的文件夹。选择后单击“确定”按钮返回“Microsoft Office受信任位置”对话框,此时会显示新选择的文件夹的完整路径。通过选中“同时信任此位置的子文件夹”复选框,可以同时信任所选文件中包含的所有子文件夹,还可以在“描述”文本框中输入说明信息。
确认无误后单击“确定”按钮关闭该对话框,在受信任位置列表中将会看到新添加的位置,例如如图1-6所示的“G:\安全的Excel宏”。
2.修改现有的受信任位置
在受信任位置列表中选择要修改的位置,然后单击“修改”按钮,可以将所选位置改为一个其他的位置。
图1-6 将所选位置添加到受信任位置列表中
3.删除受信任位置
在受信任位置列表中选择不再需要的受信任位置,单击“删除”按钮将其从列表中删除。
1.3.3 允许运行所有宏
使用1.3.2节介绍的方法只能运行位于受信任位置中工作簿所包含的宏。如果希望运行任意位置上工作簿中的宏,那么需要在“信任中心”对话框的左侧选择“宏设置”,然后在右侧选择“启用所有宏(不推荐:可能会运行有潜在危险的代码)”选项,如图1-7所示。
图1-7 对宏安全性进行全局设置
经过以上设置,无论工作簿是否位于受信任位置,用户都可以运行其中包含的宏,但同时也会带来更多的安全隐患。此外,“宏设置”类别中的选项不会对从受信任位置中打开的工作簿或加载项起作用。例如,如果在“宏设置”类别中选择“禁用所有宏,并且不通知”选项,当从受信任位置打开包含宏的工作簿时,其中的宏仍然可以正常运行。
宏设置中的另外两个选项都用于禁止运行宏,区别在于禁用的同时是否向用户发出消息通知。“禁用所有宏,并发出通知”是宏设置的默认选项,就像1.3.1节介绍的那样,当在Excel中打开包含宏的工作簿时,会在功能区下方显示消息通知,由用户决定是否允许宏的运行。如果选择“禁用所有宏,并且不通知”选项,禁用宏并且不会向用户发出消息通知。
1.3.4 禁止他人随意修改宏
在宏的安全性设置中即使禁止了宏的运行,在打开包含宏的工作簿后,用户仍然可以查看和修改宏。如果意外地修改了宏,可能会导致其无法正常运行。为了避免出现这种情况,可以通过密码为宏设置访问权限。
在Excel中打开指定的包含宏的工作簿,按Alt+F11组合键打开VBE窗口,在菜单栏中选择“工具”|“VBAProject属性”命令,打开“VBAProject-工程属性”对话框,在“保护”选项卡中选中“查看时锁定工程”复选框,在“密码”和“确认密码”文本框中输入相同的密码,如图1-8所示,最后单击“确定”按钮。
提示:本章后面将会对VBE窗口进行详细介绍。
以后再次打开受VBA工程密码保护的工作簿,并试图查看或修改VBA代码时,将会显示如图1-9所示的对话框,只有输入正确的密码才能进行下一步操作。
图1-8 为VBA工程设置密码
图1-9 查看VBA代码之前必须提供正确的密码
1.4 录制与使用宏
使用VBA的绝大多数用户几乎都是从录制宏开始的,这主要有两个原因。首先,录制宏是获得VBA代码的最简单方式,另一个原因是可以通过录制宏了解完成特定功能所需使用的Excel对象,这样就可以快速掌握VBA代码的编写技巧。无论是VBA初级用户还是有经验的VBA开发人员,都能从录制的宏中受益。本节将介绍录制和使用宏方面的内容,具体包括录制宏、运行宏、保存宏、修改宏等。
1.4.1 显示“开发工具”选项卡
“开发工具”选项卡提供了与操作宏和加载项相关的命令,但是默认没有显示在功能区中。虽然录制宏的操作不依赖于“开发工具”选项卡,但是如果要对宏进行更多的操作,则需要使用“开发工具”选项卡。
右击功能区或快速访问工具栏,在弹出的菜单中选择“自定义功能区”命令,打开“Excel选项”对话框并自动进入“自定义功能区”界面,在最右侧的列表框中选中“开发工具”复选框,如图1-10所示。单击“确定”按钮,“开发工具”选项卡将被添加到功能区中。
图1-10 选中“开发工具”复选框
1.4.2 录制宏
录制宏的操作本身很简单,首先想好要录制哪些操作,然后开启宏录制器开始录制,按照预先设想进行操作,最后停止宏录制器结束录制。这样就录制好了一个宏,以后可以通过运行这个宏来重复执行录制过程中涉及的操作。
为了确保录制的宏可用并高效,在开始录制前需要考虑一些事项。首先确定要录制的宏想要完成什么操作,然后排练要录制的操作步骤直到熟练为止。这是因为录制过程中出现的误操作会被宏录制器记录下来,以后运行宏时也会包含这些错误的操作。需要注意的是,并非所有操作都会被宏录制器记录下来。
假设希望录制从B1单元格开始在同一行中输入1月~3月的名称,即1月、2月、3月。由于本例中要在B1单元格中输入“1月”,所以录制时应该包括选择B1单元格的操作。如果录制时不包括该操作,会将在活动单元格中输入“1月”的操作记录下来。在以后运行宏时,活动单元格的位置是不固定的,这样就无法保证“1月”始终被输入到B1单元格中。
除了在单元格中输入内容以外,还需要决定是否为输入的内容设置格式,比如字体格式、数字格式或对齐格式。最后需要考虑在宏运行后活动单元格的位置。假设本例希望宏运行后的活动单元格是A2,那么在停止宏录制前,需要选择A2单元格。
考虑好以上问题后,下面就可以开始录制了。录制之前需要在“录制新宏”对话框中为宏设置一些信息,包括宏的名称、运行宏时的快捷键、宏的说明信息等内容,可以使用以下3种方法打开“录制新宏”对话框。在打开该对话框之前确保已经打开了希望包含宏的工作簿,或者新建一个空白的工作簿。
□ 单击Excel窗口底部状态栏左侧的按钮。如果没有显示该按钮,可以右击状态栏并从弹出的菜单中选择“宏录制”选项。
□ 在功能区“视图”选项卡中单击“宏”按钮,然后在弹出的菜单中选择“录制宏”命令。
□ 在功能区“开发工具”选项卡中单击“录制宏”按钮。
图1-11 “录制宏”对话框
打开的“录制宏”对话框如图1-11所示,在这里可以进行以下4项设置,其中的一些设置是可选的。
1.宏的名称
在“宏名”文本框中输入宏的名称,应该使用易于识别的描述性名称。名称的长度不能超过255个字符,而且不能包含空格、问号、叹号等符号。
2.运行宏的快捷键
在“快捷键”文本框中可以输入一个小写字母,也可以输入一个大写字母。例如,如果输入的是小写字母r,以后可以使用Ctrl+R组合键运行这个宏;如果输入的是大写字母R,则需要使用Ctrl+Shift+R组合键运行宏。
3.宏的保存位置
在“保存在”下拉列表中选择将录制好的宏保存在哪里,包含以下3个选项:
□ 选择“当前工作簿”选项,Excel会将录制的宏保存在当前工作簿中。
□ 选择“新工作簿”选项,Excel会新建一个工作簿并将录制的宏保存在其中。
□ 选择“个人宏工作簿”选项,Excel会将录制的宏保存在名为“Personal.xlsb”的特殊工作簿中。这个工作簿位于Excel程序的XLSTART启动文件夹中,每次启动Excel时也会自动启动该工作簿。由于该工作簿默认处于隐藏状态,因此启动Excel后不会显示该工作簿。如果希望录制的宏可以用于任意一个工作簿而不只是录制宏时的工作簿,那么就需要将宏保存到Personal.xlsb工作簿中。如果该工作簿不存在,Excel会自动创建。
4.宏的说明信息
为了避免以后忘记宏的用途,可以在“说明”文本框中为宏添加说明信息。
设置好所需选项后,单击“确定”按钮开始录制。Excel窗口底部状态栏左侧的“录制宏”按钮会变为“停止录制”按钮,同时功能区“开发工具”选项卡中的“录制宏”按钮也会变为“停止录制”按钮。本例要从B1单元格开始在同一行的3个单元格中输入1月~3月的名称,输入好以后让A2单元格变为活动单元格,录制过程如下:
(1)单击B1单元格,输入“1月”,然后使用类似的方法,在C1和D1单元格中分别输入“2月”和“3月”。
(2)选择B1:D1单元格区域,然后在功能区“开始”选项卡中单击“加粗”按钮,为所选区域中的内容设置加粗格式。
(3)单击A2单元格,使其成为活动单元格。
(4)单击Excel窗口底部状态栏左侧的“停止录制”按钮,结束录制。
注意:一定记得要停止宏的录制。否则如果在停止录制之前就运行宏,那么将会陷入死循环。如果出现这种情况,可以使用Ctrl+Break组合键强制中断宏的运行。
1.4.3 保存宏
完成宏的录制后,需要保存包含该宏的工作簿。不能将工作簿保存为Excel默认的.xlsx格式,因为该格式不能包含宏。如果希望保存为Excel 2007或更高版本的Excel新增的文件格式,那么必须将包含宏的工作簿保存为.xlsm格式。如果希望工作簿可以在Excel 2003或更低版本的Excel中打开,那么需要将工作簿保存为.xls格式。
打开用于保存工作簿的“另存为”对话框,在“文件类型”下拉列表选择所需的文件格式:
□ 如果要将工作簿保存为.xlsm格式,需要选择“Excel启用宏的工作簿”选项。
□ 如果要将工作簿保存为.xls格式,需要选择“Excel 97-2003工作簿”选项。
如果将宏录制到了已经保存过的格式为.xlsx的工作簿中,那么当录制好宏并按Ctrl+S组合键后,将会打开如图1-12所示的对话框,必须单击“否”按钮,然后选择“Excel启用宏的工作簿”或“Excel 97-2003工作簿”格式,才能将录制的宏保存到工作簿中。
图1-12 为了保存宏需要更改工作簿的文件格式
提示:默认情况下,在Windows操作系统中不会显示文件的扩展名。如果希望显示文件扩展名,需要在文件资源管理器中的“查看”选项卡中选中“文件扩展名”复选框,如图1-13所示。这里以Windows 10操作系统为例,其他版本的Windows操作系统与此类似。
图1-13 显示文件的扩展名
1.4.4 运行宏的多种方式
运行宏之前,可能需要更改Excel中的宏安全性设置,以确保可以正常运行宏。设置宏安全性的方法已在1.3节介绍过,这里不再赘述。在Excel窗口中要运行工作簿中的宏,需要先打开“宏”对话框,然后才能运行宏。我们可以使用以下几种方法打开“宏”对话框:
□ 单击功能区“视图”选项卡中的“宏”按钮,在弹出的菜单中选择“查看宏”命令。
□ 单击功能区“开发工具”选项卡中的“宏”按钮。
□ 按Alt+F8组合键。
图1-14 使用“宏”对话框运行宏
打开如图1-14所示的“宏”对话框,列表中默认显示了当前打开的所有工作簿中包含的宏。双击要运行的宏,或者选择宏后单击“执行”按钮,都可以运行这个宏。如果录制前为宏设置了快捷键,还可以使用快捷键运行宏,这样就不必打开“宏”对话框。
如果要修改宏的快捷键和说明信息,可以在“宏”对话框中单击“选项”按钮,然后在打开的对话框中进行修改。
除了上面介绍的运行宏的基本方法之外,还可以使用下面几种方法运行宏。
1.快速访问工具栏
可以将宏添加到Excel窗口顶部的快速访问工具栏中,这样该宏可通用于任意工作表或工作簿。右击快速访问工具栏中的任意一个按钮,在弹出的菜单中选择“自定义快速访问工具栏”命令。打开“Excel选项”对话框并显示快速访问工具栏的自定义设置界面,在“从下列位置选择命令”下拉列表中选择“宏”选项,下方会显示当前打开的工作簿中包含的宏,如图1-15所示。选择要使用的宏,然后单击“添加”按钮,将其添加到快速访问工具栏中。
图1-15 将宏添加到快速访问工具栏中
2.窗体控件
可以在工作表中嵌入窗体控件。窗体控件的优点是比ActiveX控件更简单,因为它们不具备ActiveX控件的所有功能。在功能区“开发工具”选项卡中单击“插入”按钮,然后在“表单控件”类别中选择要使用的窗体控件,如图1-16所示。在工作表中沿对角线方向拖动鼠标绘制出所选择的控件,比如绘制一个按钮控件。释放鼠标按键的同时会自动显示“指定宏”对话框,如图1-17所示,为控件选择一个要运行的宏,然后单击“确定”按钮。
图1-16 从“表单控件”类别中选择窗体控件
图1-17 为窗体控件指定宏
图1-18 修改控件上显示的文字
之后右击工作表中的窗体控件,在弹出的菜单中选择“编辑文字”命令,如图1-18所示,修改控件上显示的文字,使其更有意义。单击控件之外的其他位置,取消控件的选中状态,然后单击这个控件就会运行之前为它指定的宏。在控件的右键菜单中选择“指定宏”命令,可以修改为控件指定的宏。
3.ActiveX控件
除了窗体控件之外,还可以在工作表中嵌入ActiveX控件。在功能区“开发工具”选项卡中单击“插入”按钮,然后在“ActiveX控件”类别中选择要使用的ActiveX控件。使用类似创建窗体控件的方法在工作表中绘制出一个ActiveX控件,此时会进入设计模式。在该模式下可以选择和移动控件、设置控件的属性、为控件的事件过程编写代码。
与窗体控件不同,在工作表中插入ActiveX控件时Excel不会自动要求用户为控件指定宏,用户需要为ActiveX控件的事件过程编写代码。例如,对于命令按钮控件而言,通常需要为其编写Click事件过程的代码,如图1-19所示。在设计模式下双击工作表中的ActiveX控件,在VBE窗口中打开该控件的代码窗口,在左、右两个下拉列表中选择该控件的名称以及所需的事件过程名称,Excel会自动插入Sub语句行和End Sub语句行,用户需要在这两行语句之间输入所需的代码。
要修改ActiveX控件上显示的文本,需要在设计模式下右击控件,在弹出的菜单中选择“属性”命令,然后在打开的“属性”对话框中设置Caption属性的值,如图1-20所示。
图1-19 编写ActiveX控件的事件过程代码
图1-20 ActiveX控件的“属性”对话框
4.事件过程
事件过程允许用户在进行特定的操作或系统发生特定行为时自动运行预先编写好的VBA代码。前面介绍的在工作表中插入的命令按钮控件的Click就是该控件的其中一个事件过程。事件过程包含在工作簿、工作表、图表、用户窗体等对象所对应的代码模块中。
在VBE窗口的工程资源管理器中双击这些代码模块,打开对应的代码窗口,在左侧的下拉列表中选择一个对象,然后在右侧的下拉列表中选择该对象包含的一个事件,如图1-21所示。Excel会自动在代码窗口中添加事件过程框架,即Sub语句和End Sub语句,之后用户可以在这两个语句之间编写实现特定功能的代码。
图1-21 编写对象的事件过程
1.4.5 绝对录制和相对录制
录制宏包括绝对录制和相对录制两种模式。前面介绍的案例是在绝对模式下录制的,这也是宏录制器默认使用的录制模式。不管在哪一个工作簿中运行前面案例中录制的宏,也不管活动单元格位于哪个位置,Excel始终都会从B1单元格开始输入内容。
在相对录制模式下,活动单元格的位置记录是相对的。例如,如果当前的活动单元格是A1,开始录制后选择了B1单元格,那么宏录制器只会记录从当前活动单元格向右移动一个单元格的操作,而不会记录选中B1单元格的操作。这样在以后运行这个宏时,假设当前的活动单元格是C1,那么这个宏就会从D1单元格开始输入内容,因为D1单元格是C1单元格向右移动一个单元格后得到的单元格。
在录制选择单元格的宏之前,应该考虑使用绝对引用还是相对引用进行录制。如果希望宏可以用于不同的单元格或区域,那么通常需要使用相对引用录制。如果只希望操作固定的单元格或区域,则需要使用绝对引用录制。
要在相对模式下录制宏,需要在开始录制前,在功能区“开发工具”选项卡中单击“使用相对引用”按钮。
1.4.6 修改宏
录制好的宏虽然可以运行,但其中通常都会包含一些多余的代码,这些代码会降低宏的运行效率。因此如果了解一些VBA知识,就可以对录制好的宏进行修改,删除不必要的代码,提高运行效率。
要修改宏,首先需要打开包含宏的工作簿,然后使用1.4.4节介绍的方法打开“宏”对话框。选择要修改的宏,单击“编辑”按钮,打开VBE窗口,其中显示了所选择的宏包含的VBA代码,如图1-22所示。
图1-22 在VBE窗口中查看宏包含的VBA代码
宏本身是一组VBA代码,由Sub和End Sub以及位于它们之间的代码组成,Sub右侧的文字是宏的名称,名称右侧有一对圆括号。宏的名称就是录制宏时在“录制新宏”对话框中输入的名称。Sub语句下方以单引号开始的语句是注释语句,用于对宏的功能进行说明,运行宏时不会执行它们。注释语句下方直到End Sub语句之前的数行语句就是实现宏功能的VBA代码,可以在VBE窗口中对代码进行修改。下一节会对VBE窗口进行详细介绍。
1.5 使用VBE窗口
VBE(Visual Basic Editor)是独立运行于Excel窗口的专有窗口,编写和测试VBA代码都需要在VBE窗口中进行,因此我们有必要了解和掌握VBE窗口包含的组件以及使用方法。
1.5.1 打开VBE窗口
可以使用以下两种方法打开VBE窗口:
□ 在功能区“开发工具”选项卡中单击Visual Basic按钮。
□ 按Alt+F11组合键。
如果希望编辑指定的宏,可以使用1.4.6节介绍的方法打开VBE窗口并自动显示指定的宏。还可以在Excel窗口中右击工作表标签,在弹出的菜单中选择“查看代码”命令,打开VBE窗口并自动显示与右击的工作表关联的代码窗口。在后面的1.5.4节会对代码窗口进行详细介绍。
虽然从Excel 2007开始将Excel界面改为了功能区,但是VBE窗口一直使用早期Excel版本中的菜单栏、工具栏的布局方式。打开的VBE窗口类似如图1-23所示,由工程资源管理器、属性窗口、代码窗口和管理代码模块等部分组成。根据用户的个人设置,某些部分可能处于隐藏状态,可以使用VBE窗口“视图”菜单中的命令显示或隐藏它们。
图1-23 VBE窗口
1.5.2 工程资源管理器
图1-24 工程资源管理器
工程资源管理器如图1-24所示,它是VBE窗口中的导航工具,其中显示了当前打开的所有工作簿。每个工作簿以独立的工程显示,在每个工作簿的下方显示了工程的组成元素,比如Sheet1、Sheet2、ThisWorkbook等。可以通过单击工程资源管理器中的符号折叠或符号展开不同类别中的项目。
如果在工作簿中录制了宏,那么在与该工作簿对应的工程中会包含一个或多个模块。例如,在图1-24的“录制宏.xlsm”工程中包含一个名为“模块1”的模块。如果用户创建了用户窗体和类,在工程中还会包含窗体模块和类模块。
1.5.3 属性窗口
属性窗口显示了在工程资源管理器中当前选中的对象的相关属性,它们都是在设计时可以改变的属性。例如,在工程资源管理器中选择Sheet1,属性窗口就会显示Sheet1的属性,如图1-25所示,设置这些属性可以改变Sheet1的外观和特性。
属性窗口中的左列是属性的名称,名称的右侧是该属性的值。可以直接输入属性的值,也可以从预置选项中选择属性的值,一些属性提供了预置值。例如,Sheet1有一个Visible属性,当单击该属性名称右侧用于存放属性值的位置时会显示一个下拉按钮,单击该按钮将会显示包含预置值的列表,然后可以从中选择要为属性设置的值,如图1-26所示。
图1-25 显示当前所选对象的属性
图1-26 为属性设置预置值
1.5.4 代码窗口
所有录制的宏或手动编写的VBA代码都位于代码模块中。VBA包含两种类型的代码模块:标准模块和类模块。标准模块中的代码可用于应用程序中的任何地方,而类模块主要用于创建对象。
图1-27 代码窗口
在录制宏时由宏录制器自动创建的模块是标准模块,比如在1.5.2节提到的“模块1”。在VBA工程中默认包含了几个类模块,它们与工作簿自身或工作簿中包含的各个工作表相关联,比如Sheet1、Sheet2、ThisWorkBook。用户也可以手动创建标准模块和类模块。
在工程资源管理器中双击任意一个模块,将会打开与该模块对应的代码窗口,如图1-27所示。在代码窗口中编写代码类似于在记事本中编辑文本,编辑文本的操作方法同样适用于编辑代码窗口中的VBA代码。
在代码窗口的顶部有两个下拉列表,左侧的列表用于选择当前模块中包含的对象,右侧的列表用于选择Sub过程、Function过程或对象特有的事件过程。选择好这两部分内容后,即可为指定的Sub过程、Function过程或事件过程编写代码。在标准模块的左侧列表中只有“通用”一项。
过程是一组代码的逻辑单元,一个代码模块中可以包含任意数量的过程,每个过程用于完成不同的任务。VBA中最常使用的过程有3类:Sub过程(子过程)、Function过程(函数过程)、事件过程。宏录制器只能创建Sub过程,Function过程需要用户手动创建。事件过程是对象自带的过程,它存在于类模块中,通常不需要单独创建,只需从代码窗口的左、右两个列表中分别选择对象和事件,然后编写事件触发时要运行的代码。第2章会详细介绍Sub过程和Function过程,第12章会详细介绍事件过程。
要运行代码窗口中的VBA代码,需要将插入点定位到指定过程的范围内,然后单击VBE窗口“标准”工具栏中的“运行子过程/用户窗体”按钮,或按F5键。
1.5.5 管理代码模块
每个模块可以包含多个过程,模块为组织互不相关的过程提供了一种较好的方式。模块不能被运行,而只能运行模块中的过程。可以对模块执行以下几种操作:
□ 添加新模块:右击工程中的任意一项,在弹出的菜单中选择“插入”命令,然后在子菜单中选择要添加的模块类型,包括用户窗体、模块、类模块3种。
□ 导出模块:为了便于将编写好的代码用在其他工程中,可以将包含代码的模块以文件的形式保存到计算机磁盘中,然后在需要时将其添加到其他工程中。在工程中右击要导出的模块,在弹出的菜单中选择“导出文件”命令,然后在打开的对话框中设置文件名称和保存位置,最后单击“保存”按钮。
□ 导入模块:右击工程中的任意一项,在弹出的菜单中选择“导入文件”命令,然后在打开的对话框中选择要导入的模块文件,最后单击“打开”按钮。
□ 删除模块:对于工程中不再需要的模块,可以右击该模块,然后在弹出的菜单中选择“移除xx”命令(xx表示模块的名称)。
1.6 Excel应用程序开发流程
本节将从整体上介绍使用VBA开发Excel应用程序的基本流程和步骤,这部分内容虽然未涉及具体的VBA编程技术,但是却对从整体上管理开发任务和进度有很大的帮助,对于有一定经验的Excel开发人员也有一定的参考价值。如果读者只是编写完成单一简单任务的VBA代码,可以跳过本节内容。
1.6.1 优秀Excel应用程序的标准
没有一个绝对严格的标准来界定开发出来的Excel应用程序是否足够优秀,但是一个成功的Excel应用程序通常会符合某些既定的规则或要求。
1.正确实现预期功能
这是最基本的要求,一个应用程序必须可以正确实现预期的目标功能,否则肯定是一个失败的应用程序。
2.提供简便的操作方式
应用程序应该为用户提供友好的界面操作环境,“友好”意味着简单、方便、易懂,否则用户很可能不知道该如何使用应用程序。对于Excel 2003以及更早版本的Excel而言,友好的用户界面元素包括菜单栏、工具栏、右键快捷菜单以及快捷键;而从Excel 2007开始使用功能区代替了早期的菜单栏和工具栏,因此在Excel 2007或更高版本的Excel中需要为应用程序开发功能区操作环境。
3.为可能出现的问题预先提供解决方案
即使可以正确实现预期的功能,然而在程序的运行过程中很可能会出现各种错误,有来自程序自身的问题,也有由意料之外的用户操作导致的问题。最糟糕的情况就是由于错误而导致程序中断运行。为了使应用程序更完美,以应对各种可能的问题,这就要求开发人员必须在程序设计和测试阶段充分考虑各种可能出现的情况,然后编写错误处理程序,以便在错误发生时给予用户具有实际意义的帮助信息,而不是令普通用户费解的VBE中断模式。
4.高效执行代码
符合前面3个方面要求的应用程序已经是一个运行良好且易于使用的程序了,但是为了加快程序完成具体任务的速度,同时提高计算机软硬件资源的利用率,在设计和开发应用程序时,还应该尽可能提高代码的运行效率。
1.6.2 确定用户类型
在开发应用程序之前,首先应该确定使用这个程序的都是哪些类型的用户。应用程序是给开发者自己使用,或是为其他某个人开发的,还是要提供给某一类用户使用。根据用户类型的不同,开发应用程序所使用的具体方法和需要注意的问题都各不相同。
1.开发者自己使用
很多时候开发人员会编写一个程序供自己使用,这类程序通常可能都算不上是一个完整的应用程序,仅仅是完成某个功能或操作的一小段VBA代码。开发这样的程序通常比较简单,除了程序本身的功能之外,通常不需要考虑其他太多因素,比如Excel版本的兼容性,误操作可能导致的运行问题,甚至不需要为程序额外提供操作界面,因为开发人员可以直接在VBE窗口或“宏”对话框中运行自己编写的代码。
2.给某个用户使用
我们可能经常会收到来自别人为实现某一简单或复杂的任务的开发需求。与开发人员为自己使用而编写程序相比,为别人开发程序需要投入更多的思考。例如,需要考虑用户所用的Excel版本,用户当地的语言环境,哪些误操作可能会导致程序出错或崩溃,在用户完成某个操作之前或之后是否要给出有用的提示信息,程序中要使用的文件或数据是否存在于计算机中。以上这些问题都需要在设计应用程序时进行充分的考虑。
3.给某类用户使用
前面介绍的两类用户都是独立的个体,因此对应用程序的通用性没有太多要求。如果开发的应用程序要提供给某一类用户使用,这时就要注意程序的通用性。因为一类用户中的每一个人所使用的Excel版本、操作习惯等都各有不同,这就要求开发人员需要进行全面的构思和细致的规划。开发完成的应用程序通常以加载项的形式分发给每一个用户。
1.6.3 确定用户需求
无论应用程序的规模如何,在真正开始开发之前,需要认真收集用户的需求,即用户希望应用程序可以实现什么功能,以及如何实现。下面列出了需要从用户那里获取的重要信息:
□ 如果可能,最好直接与最终用户进行交流,从而了解他们对应用程序的各方面要求。
如果由于地理条件所限,也可以进行在线沟通。
□ 了解最终用户的计算机中安装的软硬件情况以及使用的Excel版本。
□ 了解最终用户的Excel使用经验,用户是属于初级水平,还是具有一定的操作经验,或是经验丰富的高级用户。
□ 了解用户是否需要经常对应用程序的功能进行扩展。
在了解到以上信息后,先不要急于开始Excel程序设计,而是对获取到的信息进行汇总分析并规划出一套设计方案,以便将其作为整个应用程序开发过程中的指导方针。下面列出了规划一套设计方案需要考虑的一些问题。
□ Excel版本:考虑是在Excel 2007或更高版本的Excel中开发应用程序,还是在Excel 2003或更低版本的Excel中进行开发。不同Excel版本对VBA代码有不同的限制,某些Excel对象在Excel 2007或更高版本的Excel中可以使用,但是移植到Excel 2003或更低版本的Excel中则会出错。
□ 文件结构:考虑应用程序中只包含一个工作簿还是需要包含多个工作簿。工作簿中包含一个工作表还是多个工作表。工作簿和工作表的不同组织结构会直接影响到代码的编写。
□ 数据结构:应用程序要处理的数据是存储在Excel工作簿的工作表中,还是存储在外部程序中。
□ 使用现有功能还是开发新功能:如果要实现的功能在Excel中已经提供了,那么直接使用现有功能通常要好于重新开发相同的功能。
□ 错误处理:错误处理机制是开发任何一个应用程序必备的组成部分。如果没有错误处理程序,用户在使用应用程序时就很可能频繁出现无法解决的问题,而且出现问题时显示的提示信息也不具有任何指导意义。例如,在对某个工作表进行操作之前,需要考虑该工作表是否存在,如果存在则按计划操作,否则应该向用户发出提示信息,并告诉用户接下来该如何操作。
□ 程序性能:开发的应用程序不但需要稳定运行,还应该尽可能高效。最终用户的软硬件条件可能受到某种限制,因此需要在尽可能少占用系统资源的情况下,让程序以最快的速度运行。
□ 安全问题:安全问题虽然并不影响程序的正常运行,但是对于重要的数据,可能希望将它们保护起来,以禁止其他未授权用户随意查看和修改。事先与最终用户确认是否需要对应用程序中涉及的数据进行安全保护。
1.6.4 设计用户界面
在确定好用户需求后,接下来就可以开始着手设计应用程序了。首先要做的是构思并确定用户界面,这是因为用户界面是用户与应用程序之间进行沟通的媒介。用户界面设计的优劣直接影响着用户的使用体验和操作效率。
对于Excel 2003或更低版本的Excel而言,设计用户界面的主要任务是定制菜单栏、工具栏和鼠标右键快捷菜单。这些定制虽然也可用于Excel 2007或更高版本的Excel中,但是由于这些Excel版本采用了功能区界面,因此定制的菜单栏和工具栏会出现在功能区的“加载项”选项卡中。
如果应用程序只用于Excel 2007或更高版本的Excel中,那么除了鼠标右键菜单之外,定制功能区界面的方法与定制菜单栏和工具栏将大为不同。如果应用程序可能会用于多个不同的Excel版本中,那么可以设计多版本兼容的界面操作环境,首先检测用户当前使用的Excel版本号,然后根据不同版本分别加载功能区界面或加载菜单栏和工具栏界面。
图1-28 自定义对话框
构思用户界面时,需要考虑应用程序是直接以工作表或工作簿为操作界面,还是使用自定义的对话框。如果使用后者作为应用程序的界面,则需要开发者创建用户窗体,并在其上添加所需的控件,从头开始设计对话框的外观和功能。如图1-28所示是在启动应用程序后显示的登录窗口,只有输入正确的用户名和密码才能继续使用该程序。
如果应用程序准备以工作表作为与用户交互的主界面,那么可以在工作表中添加窗体控件或ActiveX控件,以便通过这些控件来实现数据的输入、选择和输出。还可以为应用程序设置快捷键来作为界面操作的替代方式,只需按下定义好的按键组合,即可执行相应的操作。
1.6.5 编写代码
编写代码是整个开发过程中最重要的工作。在开始编写代码前,需要详细考虑整个应用程序的结构。使用VBA开发的应用程序通常由多个模块组成,这些模块除了工程中默认自带的工作表模块和工作簿模块之外,还可以根据需要在工程中插入标准模块、窗体模块和类模块。应该先规划应用程序由哪些模块组成,每个模块实现应用程序中的哪些功能。确定好这些内容后,接下来就可以开始编写代码了,编写代码的工作需要在VBE窗口中完成。
1.6.6 测试应用程序
对应用程序功能的测试通常与编写代码同时进行。很少有人会在编写好全部代码后才开始进行测试工作,这样会加大测试的难度,不利于错误的排查。更好的方法是在编写好完成独立功能的代码段后就立刻进行测试,以便可以及时发现问题并进行修复。当完成所有代码的编写工作后,测试工作就会相对比较轻松。
在完成应用程序的所有开发工作后,接下来需要对整个应用程序进行全面系统性的测试。测试通常分为内部测试和Beta测试。内部测试是指开发人员对应用程序的各部分功能进行测试,这一步是至关重要的。与之前对某个代码段的测试不同,对整个应用程序的测试更复杂,在测试过程中要考虑到任何可能的操作或情况,对各部分功能进行不同的测试,以发现任何可能存在的问题。
经过开发人员的测试后,如果应用程序能够正常运作,那么接下来就可以将应用程序分发给一些感兴趣的用户进行Beta测试,他们可能就是应用程序的最终用户。在Beta测试阶段,很可能发现一些遗漏或隐藏的问题。例如,程序假定某个工作表存在,但实际上用户在执行程序之前已经意外地删除了该工作表。通过Beta测试,可以发现这类在开发阶段没有充分考虑到的问题。
1.6.7 修复错误
Excel应用程序的错误主要分为两类:编译错误和运行时错误。编译错误是指在代码非运行阶段出现的错误,通常是VBA语法错误,在编写代码的过程中VBE会自动发现这类错误并提示用户。例如,代码中的Sub过程名以数字开头,VBE就会检测出该错误并显示如图1-29所示的提示信息,同时自动高亮显示代码中的出错部分。
图1-29 编译错误
相对于编译错误而言,运行时错误需要在运行代码时才能被检测到。例如,如果当前没有打开名为“销量汇总”的工作簿,那么运行下面的代码就会显示错误提示信息,但是在编写代码时并不会提示这个错误。
MsgBox Workbooks("销量汇总").Name
除了编译错误和运行时错误之外,还有一类比较隐含的错误,这类错误在程序运行时不会显示出错提示信息,但是运行结果却会和预期结果截然不同。编写的代码本身并无语法错误,运行代码时也没有出现运行时错误,但是运行结果是错的。排查这类问题只能是检查应用程序的每一部分代码的运行结果是否正确,通过分段测试以便逐步将隐藏的错误找出来。
1.6.8 发布应用程序
修复好检测到的所有错误后,接下来就可以发布应用程序了。在发布之前,应该将所有的开发工作记录归档,以形成书面材料。这些资料有两个非常重要的作用,第一,可以为开发人员在日后修改或升级程序提供清晰明了的帮助,时隔多日以后开发人员可能已经忘记了程序最初的设想、结构或是某部分代码的作用,通过这些辅助文档,开发人员可以很快熟悉整个应用程序的工作原理和机制;第二,详细的归档资料可以给最终用户使用应用程序提供有用的指导和帮助。
当然,开发人员自己保留和提供给用户的文档内容并不相同。相对而言,提供给开发人员的文档会包含整个应用程序开发过程的完整技术细节,而提供给最终用户的文档通常只包含应用程序的使用方法。
编写好相关文档后就可以发布应用程序了。发布应用程序有很多种方法,最简单的一种方法是将应用程序所在的工作簿转换为加载项,然后分发给用户并进行安装。另一种更为专业的方法是开发一个安装程序,这样用户只需双击安装程序即可自动进行安装,对最终用户而言操作更方便。
发布应用程序后并不意味着所有开发工作的终止,因为在将来的某个时候,用户很可能会根据实际需求,要求开发人员对应用程序的功能进行扩展或整体升级。此时就会用到之前整理归档的开发文档,开发人员可以很快熟悉应用程序最初的设计意图,以及各部分代码的工作机制,从而可以很容易在原来程序的基础上进行功能扩充或完整升级。