1.2 利用宏简化日常工作
录制宏是指利用宏记录器将当前的所有操作记录下来,以代码形式描述所进行的操作。回放该代码时可以重新执行所记录的所有操作,实现与预期一致的效果。
录制宏有诸多技巧,不过鉴于宏自身的局限性,本节仅对录制宏与调用宏做简要介绍,VBA才是本书的重点。另外本节主要介绍宏的使用方法,对于宏代码并不深入解析,在后面的章节会有相关的理论教学。
1.2.1 三分钟学会录制宏
录制宏表示记录当前操作,有“相对引用”和“绝对引用”之分,需要根据需求选择采用何种方式录制。
以“绝对引用”方式录制宏时将如实记录所操作的单元格的绝对地址,例如“B5”、“$F$10”在VBA中都属于绝对地址。当调用该宏时,总是如实地执行相同操作,不受活动单元格的地址所影响。而以“相对引用”方式录制宏时,总是以活动单元格为参照原点来记录操作对象地址,所以当后期调用该宏时会以调用宏时的活动单元格作为参照原点。基于此,调用“相对引用”方式记录的宏和调用“绝对引用”方式记录的宏有所不同,前者不需要任何规则,总是按既定流程执行;后者则受活动单元格影响,在不同单元格调用宏将得到不同的结果。两者相比,采用“相对引用”方式录制的宏更灵活、更强大,不过在调用时需要格外小心。
下面以“相对引用”和“绝对引用”两种方式录制宏,操作步骤包括:选择A1单元格、录入字符串“宏与VBA”,然后将A1单元格设置为字体加粗、下画线和20号字体,最后让A列自动适应列宽。
注意:【录制宏】菜单在【开发工具】选项卡中,对于普通用户而言开发工具并不常用,所以微软未将它显示在功能区中,需要进入Excel选项对话框手动调出该选项卡。具体请参考图1.4的操作步骤。
↘ 绝对引用
新建空白工作簿并选择B1单元格,然后再录制宏。
图1.4 调出开发工具选项卡
采用绝对引用方式录制宏的步骤如下。
1 选择菜单【开发工具】⇨【录制宏】,打开“录制新宏”对话框,将对话框中的宏名保持默认的“宏1”,快捷键设置为【Ctrl+q】,并对宏加以说明,如图1.5所示。
图1.5 指定宏的快捷键和名称
2 选择A1单元格,并录入文本“宏与VBA”,然后单击回车键确认录入。
3 选择A1单元格,然后分别单击【开始】选项卡的【字体】组中对应的菜单,将A1单元格设置为加粗、下画线,以及20号字体。
4 双击A列与B列中的分界线,使A列自动调整列宽。
5 单击【开发工具】⇨【停止录制】。
至此,已经完成录制宏,可以随时通过快捷键【Ctrl+q】执行此宏。
使用【Alt+F11】组合键进入保存宏代码的界面,双击左边工程资源管理器中的模块1,可以看到如下代码,如图1.6所示。
Sub宏1() ' 宏1 宏 ' 对A1赋值并设置格式 ' 快捷键:Ctrl+q Range("A1").Select Application.FormulaBarHeight = 1 ActiveCell.FormulaR1C1 = "宏与VBA" Range("A1").Select Selection.Font.Bold = True Selection.Font.Underline = xlUnderlineStyleSingle With Selection.Font .Name = "宋体" .Size = 20 .Strikethrough = False .Superscript = False .Subscript = False .OutlineFont = False .Shadow = False .Underline = xlUnderlineStyleSingle .ThemeColor = xlThemeColorLight1 .TintAndShade = 0 .ThemeFont = xlThemeFontMinor End With Columns("A:A").EntireColumn.AutoFit End Sub
图1.6 保存宏代码的位置
↘ 相对引用
删除刚才在A列录入的数据,然后以相对引用方式再次录制宏,目的是观察两种录制方式所产生的宏代码的差异,以及比较两种宏代码执行方式的异同。
仍然先选择B1单元格,然后再录制宏。
1 单击【开发工具】⇨【使用相对引用】,从而切换到相对引用状态。
2 单击【开发工具】⇨【录制宏】,在弹出的对话框中保持默认的宏名“宏2”,将宏的快捷键设置为大写字母“Q”,从而使快捷键变为【Ctrl+Shift+q】,然后对宏添加说明“以相对引用录制宏”。
3 选择A1单元格,重复“绝对引用”中的步骤3、4、5。
4 使用【Alt+F11】组合键进入宏代码存放界面,在模块2中将看到如下代码。
Sub宏2()
' 宏2 宏
' 以相对引用录制宏
' 快捷键:Ctrl+Shift+q
ActiveCell.Offset(0, -1).Range("A1").Select
ActiveCell.FormulaR1C1 = "宏与VBA"
ActiveCell.Select
Selection.Font.Bold = True
Selection.Font.Underline = xlUnderlineStyleSingle
With Selection.Font
.Name = "宋体"
.Size = 20
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleSingle
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
.ThemeFont = xlThemeFontMinor
End With
ActiveCell.Columns("A:A").EntireColumn.EntireColumn.AutoFit
End Sub
从以上两组代码可以明显地比较出两种引用方式下录制的宏代码的差异。
注意:本章学会录制宏并懂得执行宏即可,没必要纠结于能否看懂代码。在后面的章节中会有关于VBA的基础理论,当学会VBA后,足以编写复杂数十倍的代码。
本例案例文件请参考:..\ 第1章\ 1-3录制宏并调用.xlsm
1.2.2 执行宏的方法
执行宏有多种方法,其中最简单的莫过于使用快捷键。即录制宏时对宏指定快捷键,录制完成后通过快捷键调用宏代码。
以上两个宏已经设置了【Ctrl+q】和【Ctrl+Shift+q】两个快捷键。
通过以下步骤可执行“宏1”。
1 清空工作表中的所有数据,便于观察执行宏之后的效果。
2 选择C5单元格,按下【Ctrl+q】组合键。此时光标将自动定位于A1单元格,同时在A1单元格产生加粗、带下画线且字号为20号的字符串“宏与VBA”,同时将A列调整为自动适应列宽。
3 清除A列,选择G20单元格,再次使用【Ctrl+q】组合键执行宏,可以发现两次执行的效果完全一致,如图1.7所示。
图1.7 调用绝对引用宏的执行结果
由此可见,“绝对引用”的特性是总是指向固定目标,不受活动单元格位置所影响。
接下来,通过3个步骤调用以“相对引用”方式录制的宏,并了解其特性。
1 清空工作表中的所有数据,便于观察执行宏后的效果。
2 选择C5单元格,按下【Ctrl+Shift+q】组合键,光标将自动定位于B5单元格,同时在B5单元格产生加粗、带下画线且字号为20号的字符串“宏与VBA”,同时将B列调整为自动适应列宽,效果如图1.8所示。
图1.8 调用相对引用宏的执行结果
3 选择G20单元格,然后再次使用【Ctrl+Shift+q】组合键执行宏,光标将自动定位于F20单元格,同时在F20单元格产生加粗、带下画线且字号为20号的字符串“宏与VBA”,同时将F列调整为自动适应列宽。
由此可以印证,调用“相对引用”方式录制的宏时会受活动单元格的地址所影响。在本例中,由于录制时被操作单元格在活动单元格左边的一个单元格(录制前的活动单元格是B1,操作对象是A1),所以执行宏时的操作对象总是活动单元格左方一个单元格,而非操作A1单元格。这个特性有时是优点,能使宏具备更多的灵活性;有时又是缺点,调用宏时必须小心翼翼,避免操作对象错位。
1.2.3 两种方法读懂宏代码
从上面的录制宏并调用宏可以初步了解宏的强大功能,那是否能读懂其代码含义呢?
完全明白所有代码的含义通常需要3到6个月的经验积累,而非一朝一夕之功。不过通过以下分析有助于读者了解宏代码的大致含义。
宏代码由以下四部分组成,如图1.9所示。
图1.9 宏代码的结构
第一部分是宏的声明语句,利用Sub声明宏的名称,并带有一个用于存放参数的容器——空括号,例如本例中的“Sub宏1()”。不过录制宏时不能产生参数,使用VBA编程才需要参数,所以宏过程的名称只有括号,括号中总是保持空白。
第二部分是注释,即代码中绿色的三行文字,它用于描述当前宏的名称、快捷键和录制宏时输入的说明文字。如果录制前未添加说明,该行将显示空文本。
第三部分是宏的核心,包含注释行之后直到倒数第二句的所有行,这些代码记录了录制宏过程中的所有操作信息,可以通过“播放”这些代码重现录制宏时的操作过程。
第四部分即最后一句——“End Sub”,表示结束宏过程。
其中第一和第四部分仅是一段程序的外壳,重点在于壳中的第三部分,所以大家往往说“第一句代码”、“第二句代码”是针对第三部分而言,而非从Sub语句开始。本节中前面阐述的读懂宏代码也是针对宏代码中的第三部分而言。
了解录制宏所产生的每句代码的含义,通常有两种方式:逐句执行和查询帮助。
注意:VBA中将一段程序称为过程,Sub语句声明的程序称为子过程,Function语句声明的程序称为函数过程,即自定义函数。
↘ 逐句执行
逐句执行代码可以观察代码与操作对象的对应关系,了解每句代码的大致功能。
假设第一句代码是新建工作表,那么执行第一句后工作表界面会多出一个新表,根据此变化可以判断当前语句的功能是添加新表,这给新手学习代码提供了较大的帮助。
以执行“宏2”为例,读懂宏代码的方法如下。
1 将工作表界面和代码窗口界面调整为各占屏幕的二分之一大小,方便自己能同时查看代码和工作表界面的所有可见单元格。图1.10为调整好的界面。
图1.10 并排工作表窗口与代码窗口
工作表界面
2 选择工作表中的E5单元格。
3 激活代码窗口,用鼠标左键单击代码中的任意位置,相当于将“宏2”设置为当前宏。
4 按快捷键【F8】单步执行宏,此时Excel用黄色背景标示“Sub宏2”,表示即将执行该行代码。
5 再次按下【F8】键,Excel将执行“Sub宏2”语句,然后用黄色背景标示第二句(由于注释不属于宏代码,不需要执行,所以执行宏后会忽略)。
6 第三次按下【F8】键,Excel才真正通过宏执行操作,即运行代码中的第一句(忽略Sub和End Sub组成的程序外壳),执行对应的功能。
当第三次按下【F8】键后,可以发现工作表中的活动单元格已经由F5变为E5,这意味着代码“ActiveCell.Offset(0, -1).Range("A1").Select”的功能是选择左边一个单元格。
7 第四次按下【F8】键,可以发现活动单元格E5中产生了字符串“宏与VBA”,这意味着代码“ActiveCell.FormulaR1C1 = "宏与VBA"”是对活动单元格赋值。
8 第五次按下【F8】键,可以发现活动单元格中的字符产生了加粗效果,这意味着代码“Selection.Font.Bold = True”能对单元格的字符加粗……
按以上方式逐句执行代码,可以根据工作表的变化了解代码的含义。
然而,有时执行某些语句时可能会看不到任何改变,所以此方法不能确保用户每次都准确地猜出代码的含义。例如代码“Strikethrough = False”的含义是去除单元格的删除线,当单元格的字符本就不存在删除线时,屏幕上将不会有任何反应,那么也无法通过目测屏幕变化来猜测代码的含义。所以VBA提供了第二种协助用户读懂宏代码的方法——查询帮助。
↘ 查询帮助
录制宏产生的代码大多可以通过“重播”代码来识别每句代码的含义,然而这只是根据被操作对象的变化猜测,猜测的结果并不总是准确的,况且,如果执行某些代码后屏幕上不产生任何变化,那么将无从猜起。所以要精确地认知每句代码、每个单词的含义,可以查询Excel自带的帮助系统。
查询帮助也包含两种方式,一种是选择需要了解的单词例如Offset,按下【F1】键即可。例如图1.11中左边部分显示了被选中的单词为Offset,右边的帮助窗口内容正好是Range.Offset属性的相关信息,包括语法、参数含义和示例。通过帮助中的描述,我们足以了解Offset的含义及用法。
图1.11 调用Offset的帮助
不过上述方法无法查询到所有宏代码中的单词含义,例如选中ActiveCell后单击【F1】键,虽然能打开帮助窗口,但窗口中并不提供ActiveCell的相关信息。所以查询帮助还有第二种方法,即在帮助窗口的“键入要搜索的字词”文本框中输入单词后单击【Enter】键即可。
例如在按【F1】键打开帮助窗口后,搜索ActiveCell可得到如图1.12所示结果,在图中未直接描述ActiveCell的帮助信息,而是罗列出与ActiveCell相关的属性或者方法供用户选择。这是因为ActiveCell用在不同地方有不同的解释,需要用户指定完整的查询条件才能列出说明。当选择图1.12中的“Window.ActiveCell”后能得到图1.13所示的帮助信息,在该帮助中有功能描述、语法,补充说明,有时还会提供1~3个示例。
图1.12 查询ActiveCell的帮助
图1.13 查询Window.ActiveCell的帮助
1.2.4 宏的优缺点分析
根据对前面三个小节的学习,我们对宏已经有了基本的认识,总体来说宏的优缺点如下。
↘ 优点
宏严格来说不是程序,录制宏也不算编程。但是录制宏能实现与编程相近的功能,让原本需要多个步骤的工作一键完成,而且宏代码可以反复调用。
录制宏时可以按操作顺序如实地记录所有操作信息,所以执行宏时总是产生与录制时的操作完全一致的效果。而在实际工作中,当步骤较多且需要重复操作时,手工操作较难确保每次的操作顺序一致,也难确保结果的保存位置、大小等参数一致,甚至可能会遗漏某个操作步骤。
宏是以代码的形式存在的,而代码可以调整顺序或者增删语句,所以当工作需求变化时,稍微调整宏代码即可完成所有工作,而不需要重新录制可能需要几十个步骤才能完成的宏。
另外,学习录制宏仅需三分钟,在录制宏时只需要做基础操作,不需要管代码的含义、语法和思路,宏代码会自动生成,这比其他不带录制功能的编程语言有更多的优越性。
↘ 缺点
微软公司在Office平台中推广宏的时间仅短短几年,之后就用VBA替代了宏的地位,无疑是宏的局限性阻碍了它的发展,而VBA刚好可以弥补宏的缺陷,它在灵活性、效率和全面性方面都远远超过宏。
首先,并非所有操作都能通过录制宏产生相应的代码,这意味着宏的全面性不足。
其次,录制宏时通常会产生一些冗余代码,从而降低宏的执行效率。例如前面两次录制宏时,设置字号为20这一个步骤所产生的代码包括了设置字号、字体、删除线、阴影和主题颜色等。
With Selection.Font .Name = "宋体" .Size = 20 .Strikethrough = False .Superscript = False .Subscript = False .OutlineFont = False .Shadow = False .Underline = xlUnderlineStyleSingle .ThemeColor = xlThemeColorLight1 .TintAndShade = 0 .ThemeFont = xlThemeFontMinor End With
如果采用VBA编程,只需要“Selection.Font.Size = 20”一句代码即可满足工作需求,所以宏与VBA在效率上差异较大。
再次,录制宏时只能记录操作,宏代码不会执行判断。例如可以录制“删除A列”的操作,但是无法通过录制宏完成“假设A列空白则整列删除”这类需求。而且,即使是能录制的操作也仅仅是针对单一的操作,可循环的操作无法录制成功。例如删除工作表200 列数据中所有奇数列的值,如果采用录制宏产生代码,那么录制时需要删除100次,产生超过200行的代码。如果采用VBA编程,仅需要以下三句代码即可完成,而且执行时间将节约90%以上。
Sub删除前200列中奇数列的值() '此过程代码放在模块中执行 For i = 1 To 200 Step 2 '从1循环到200,步长值为2(即隔两列删除一列的值) Columns(i).Clear '将第i列的值删除 Next i '执行下一轮循环 End Sub
最后,录制宏的灵活性差。不管是单元格地址、还是工作表、图片、图表,录制宏时都采用固定的名称,一旦实际情况变化时,录制宏产生的代码将会出错。例如在空白工作表中录制创建矩形并设置其格式的宏,Excel会自动将图形命名为“矩形1”,并对“矩形1”设置格式。然而实际执行宏时环境发生了变化,宏代码在调用“矩形1”时则可能失败。只有采用VBA编程才能使代码具有灵活性、自动适应环境的变化,同时让代码可防错,通用于不同环境。所以本书的重点是VBA教学,而不局限于应用宏。
1.2.5 如何发挥宏的长处
根据前面的分析,宏能实现操作自动化,但也存在大量的问题,这些问题决定了宏无法适应工作需求中的复杂性和多变性,更不能通过录制宏产生通用的程序。然而在如今VBA疯狂发展的时代里,宏不再发挥其作用了吗?
其实不然,虽然工作中VBA已经全方位取代了宏,但是学习VBA不可能迈过录制宏这道门槛。在学习过程中,每个人都有从低到高、由浅入深、循序渐进的阶段,总是从录制宏开始接触宏代码,并开始接触编程,然后逐步熟练掌握VBA的语法。
此外,即使是VBA高手,已经可以熟练编程时仍然会经常录制宏。
换言之,由于宏的局限性致使其失去了制表工作中的实际应用价值,但是仍然可以通过以下方法发挥宏的优势。
对于初学VBA者而言,可借助录制宏了解工作中界面的各种操作所对应的VBA代码,进而从帮助中查看代码的含义,学习其具体的语法,从而大大提升学习速度。
在多数情况下,录制宏能产生所有需要的代码,直接使用录制宏的代码或者删除其中的冗余代码即可用于正常工作(冗余代码即不必要的代码,删除它也能实现同等功能)。
而对于包含循环、判断之类的要求,虽然录制宏不能产生循环和判断语句,但是可以通过录制宏产生循环与判断语句之外的代码,当录制好宏以后手动添加循环或者判断语句即可,从而节约至少60%的工作量。
也就是说,所有能录制的操作都可以不用学习相关的VBA代码,录制宏可自动产生代码。需要学习的内容是不能录制的这部分,包括Excel的事件、条件语句、循环语句、防错语句、变量与常量的用法等,而这些知识点仅占VBA编程的20%左右。另外还需要学习的是设计窗体、菜单、功能区等知识点。
与其他编程语言相比,VBA是最简单的。由于可以录制宏,能节约至少60%的精力,这就避免了花大量时间背诵代码。可以需要什么就录制什么,即时产生所需代码。数据有效性、排序、筛选、定义格式、生成图表、创建工作表等都不需要耗费精力去学习和记忆,需要记的仅仅是If Then、For Next、For Each…Next、With…End with、Do Loop等几组简单的语法而已。
此外,通过录制宏能快速得到程序代码,稍加修改即可正常应用。这对于新手来说极为重要,能提升自信心和成就感,而成就感是继续学习的动力。
对于VBA熟手而言,在编程过程中同样需要录制宏。
初学VBA者是通过录制宏来学习代码的书写方式,例如排序、筛选的代码不会写,花10秒录制宏就会了;VBA熟手则是通过录制宏快速获取代码,节约手工书写所花费的时间,也避免记错单词带来的失误,同时还可以让编程者释放背诵代码的压力。由于可以录制宏,所以所有与工作表、单元格、图表等相关的属性、方法和事件名称统统不用记忆,需要时录制即可,这让程序员得以从背诵代码的工作中解脱出来。
总结为一句话:实际工作中录制宏的目的不是使用宏,而是通过录制宏产生对应的代码,节约学习和录入代码的时间,也可以提升录入代码的准确性。