什么是VBA?
Visual Basic for Applications(VBA)是 VisualBasic 的一种宏语言,是微软开发出来在其桌面应用程序中执行通用的自动化(OLE)任务的编程语言。主要能用来扩展 Windows 的应用程序功能,特别是Microsoft Office软件。
以上是 VBA 的百科定义,说简单点,VBA 是运行在 Microsoft Office 软件之上,可以用来编写非软件自带的功能的编程语言。Office 软件提供丰富的功能接口,VBA 可以调用它们,实现自定义的需求。基本上,能用鼠标和键盘能做的事情,VBA 也能做。
正如前文所述,VBA 可以运行在 Office 软件上,包括 Excel、Word、PPT、Outlook 等。VBA 语言在 Office 软件中是通用的,基本语法和用法都相同。但是每一个软件具有自己独有的对象,例如 Excel 有单元格对象,Word 有段落对象,PPT 有幻灯片对象。
回到 Excel VBA,用它可以编写自定义函数,插入任意图表、批量处理大量数据单元格,编写插件自动化工作。甚至可以编写基于 Excel 的复杂的管理系统,其功能可以媲美桌面软件。
VBA 与宏有什么区别?
在学习 VBA 过程中,经常会出现一个说法,「宏」。简单的说,宏是一段可以运行的 VBA 代码片段,也可以说是一个简称,并没有特别的不同之处。所以学习 VBA 时,不用纠结于两者到底有什么区别,只需要记住一点,宏是使用 VBA 编写的一段代码片段。
学习 Excel VBA 有什么用处?
前面我们说到,Excel 中,VBA 几乎可以实现任何功能,从简单的数据处理,到批量数据分析,再到与 Office 其他软件交互,甚至与操作系统交互实现复杂的功能,VBA 几乎都可以胜任。以下是 Excel VBA 几个典型的用途。
节省时间:只需一次点击就可以重复执行任意数量的操作。例如,现在要新建 20 个工作表,手动操作可能需要一分钟的时间。使用 VBA 只需一秒即可。
自动化任务:只需一次点击就可以按预先设置好的步骤,自动完成操作。例如,插入一个图表并设调整格式,根据其复杂程度,可能需要多达几分钟时间。而使用VBA编写调整步骤,一次点击,几秒内即可完成所有的操作。
减少错误:相比于手动操作出现的错误,只要正确编写 VBA 代码,执行过程中就不会出现错误。例如,从一区域中筛选指定数据,并复制到另外一个位置,手动操作可能会出现漏选的可能。但是使用 VBA,极短的时间内正确无误的完成操作。
与其他软件交互:使用 VBA,可以在 Excel 里创建、更新 Word、PPT 等文件。还可以与系统交互,做到复制、移动、重命名其他文件等操作,无需打开其他文件。
VBA基础
Excel VBA 中的 几 个基本概念
在正式接触实际的 VBA 代码之前,对 Excel VBA 中的一些概念有初步的认识,将会有助于学好 Excel VBA。
其中最基本的概念将在以后的教程中反复出现,是学会 VBA 的必备基础。而其余的部分,会随着学习的深入,也会逐步做介绍。
Excel VBA 基本原理
说到 Excel VBA 的基本原理,自然的出现两种基本概念,一是 VBA 语法层面,一是 Excel 层面。那么这两者有什么区别,参考下面的图。
简单的总结一下上图:Excel 是一个对象,这个对象包含很多属性和子对象,而 VBA 是可以操作这些对象的工具,实现各种各样的效果。例如,Excel 包括 Range 对象,即单元格对象,使用 VBA 可以改变单元格对象的填充颜色属性。用代码表示如下。
'A1 单元格的填充颜色设置为颜色号为 49407 的颜色
Range("A1").Interior.Color = 49407
上面的代码现在不懂没关系,在这里使用代码简单的演示一下 Excel 中的对象和 VBA 的关系。
Range(“A1”)、Interior、Color 等是 Excel 具备的对象和属性;
对象和属性的操作,是通过 VBA 语言实现的,即上面是一行 VBA 代码。中间的等号(=)是 VBA 语言的赋值符号,也是能改变单元格填充颜色的关键所在。
以上就是 Excel VBA 的基本原理。下面从 VBA 语言层面和 Excel 对象层面,分别介绍相关基本概念。
VBA 语言中基本概念
注释
注释是代码中不会被执行的一段代码。注释是几乎所有编程语言具备的功能,VBA 也不例外。
VBA 中的注释以英文单引号 (‘) 开头,后面接注释的内容。从单引号开始的部分不会被执行。
'我是一行注释
注释,正如字面意思,用来对代码进行解释。在写代码过程中,对代码进行注释是好的习惯,有助于自己或别人,更好的理解已经存在的一段代码。
关于注释的使用,在往后的教程中可以看到很多用法,可以进一步加深理解。
变量
变量是存储数据的一种表达方式。在程序开始,可以声明一个变量,指定变量的类型(数字、文本、逻辑值等),并给变量赋值。在程序其他地方,就可以用该变量,使其存储的值参与运算。
以下方代码为例:
'声明一个文本类型的变量
Dim s As String
'给 s 变量赋值,即 "Hello World"
s = "Hello World"
'在 A1 单元格写入 s 变量存储的数据
Range("A1").Value = s
可以看到,s 变量存储 “Hello World”文本,该文本在程序中就可以用s 变量表示。这部分内容在「变量、类型和运算符」章节中详细介绍。
程序结构
程序结构表示程序的运行方式。VBA 正是因为存在多种代码结构,才能实现各类复杂的数据计算。常用的代码结构以下三种:
顺序结构
条件结构
循环结构
顺序结构,顾名思义,程序按照顺序执行。在 VBA 中就是从上到下,一行一行地执行。
条件结构,代码中的指定部分,按照某个条件,选择性地执行。即,条件为真时,执行指定代码;否则跳过该部分代码,不执行。
循环结构,代码中的指定部分,按指定次数,循环执行。这是为什么 VBA 的效率高的一个原因,因为它能将相同的操作,自动按任意数量重复执行。
关于程序结构的内容,在「程序结构」中详细介绍。
过程和函数
过程或函数包含多行代码,是组织代码的两种方式。一般情况下,一个过程或函数只包含实现一个功能的相关代码。如果一个过程或函数实现多个功能,建议将代码分成多个过程或函数。
过程和函数都可以执行一段代码,主要区别是,执行完代码后,函数能返回一个值,而过程不能返回。更多内容将在「过程和函数」章节介绍。
数组
数组表示一组同类型的数据的集合,是 VBA 中最重要的概念之一。以下面的代码为例:
'创建数组
Dim s(1 to 4) As String
'给数组的元素赋值
s(1) = "Excel"
s(2) = "Word"
s(3) = "PowerPoint"
s(4) = "Outlook"
对象
对象是一个物,它可以是一个事、一个物体、一个概念、一个名词。对象包含描述静态信息的属性和对对象可以操作的方法。
以生活中的对象为例子,汽车是一个对象。汽车的车牌号、油量、里程等是汽车的属性;开车、加油、换车牌等是汽车的方法。
在 VBA 中也是类似。工作表(Worksheet)是一个对象,它具有名称、标签颜色等属性,有添加、删除等方法。Excel VBA 中对象将在「Excel VBA 对象模型」一章中详细介绍。
Excel VBA 中的基本概念
Excel 对象模型
在上面对象一段中,说到了工作表(Worksheet)对象。其实 Excel 本身是就是一个对象,是 Excel 中的最大的对象,使用 Application 表示。Application 对象又包含工作簿(Workbook)对象,工作簿(Workbook)对象又包含工作表(Worksheet)对象,而工作表(Worksheet)对象又包含其他的子对象。
上面一段基本描述了 Excel VBA 对象模型,即是一种树状结构,多个对象通过有逻辑的层次结构组织在一起。
更多内容在「Excel VBA 对象模型」一章中详细介绍。
常用 Excel 对象
Application 对象,表示 Excel 应用程序。
Workbook 对象,表示工作簿对象。
Worksheet 对象,表示工作表对象
Range 对象,表示单元格区域对象。
模块
模块是包含一个或多个过程或函数的内部组件。一个工作簿内包含的模块数量没有限制,一个模块内包含的过程或函数数量也没有限制。模块用来作为保存过程或函数的容器,这些过程和函数通常应用于整个工作簿。
通过把多个过程和函数,合理的放置在不同的模块,可以使整个 VBA 代码逻辑更清晰、更易于阅读和理解。
用户窗体
用户窗体是 VBA 代码与使用者交互的用户界面。Excel VBA 提供很多基本的窗体控件,可以制作复杂的用户界面。最典型的,Excel 中设置单元格格式的窗口界面,就是一个用户窗体。
最基本的窗体控件包括:
文本控件
按钮控件
列表控件
输入控件
关于窗体的更多内容,将在「用户窗体」一章详细介绍。
其他基本概念
VBA 编辑器
VBA 编辑器是 Excel 中写 VBA 代码的地方。编辑器中可以进行下列操作:
编写代码
修改已有的代码
插入新的模块,编辑模块中的代码
插入用户窗体,设计窗体界面
运行代码
调试代码
这部分内容将在「Excel VBA 编辑器」章节详细介绍。
启用 Excel 开发工具教程
进行 Excel VBA 开发,需要使用「开发工具」选项卡包含的各项命令。默认情况下,「开发工具」选项卡是隐藏状态,需要手动启用。第一次启用后,在以后每次打开工作簿时,都会自动显示该选项卡。
启用开发工具
第一步:在功能区任意一区域点击右键,弹出的菜单中选择「自定义功能区」。
第二步:在右侧选项卡列表中,找到「开发工具」并勾选。
第三步:点击确定,这时在功能区可以看到「开发工具」了。
认识开发工具
开发工具选项卡共包含三组命令,其中代码组的命令是使用最频繁的一组命令。加载项组和控件组的命令使用的较少,这部分在学习完基础知识后,详细介绍。
Visual Basic:打开 VBA 编辑器,快捷键是 Alt + F11
宏:打开宏列表,并且可以对列表中的宏进行编辑,例如运行、修改、删除等。这里的宏,就是我们在上一节中说到的过程。
录制宏:将键盘和鼠标操作,自动转换成 VBA 代码。这个功能在实际的开发过程中非常有用。具体用法以后的文章中介绍。
使用相对引用:录制宏时的设置选项。
宏安全性:设置 Excel 如何对待包含 VBA 代码的工作簿。因为存在一些恶意的代码,所以一般将宏安全性设置为禁用。
如何打开 Excel VBA 编辑器?
Excel 进行 VBA 开发在 VBA 编辑器中进行。第一步将会是打开 Excel VBA 编辑器。本节介绍打开 Excel 编辑器的三种方法。
方法一:从功能区开发工具打开
点击开发工具选项卡Visual Basic命令。
如何启用 Excel 开发工具选项卡,阅读→启用 Excel 开发工具
方法二:从工作表名称打开
在任意工作表标签上方,右键,在弹出的选项列表中,选择「查看代码」。
方法三:使用快捷键打开
使用快捷键 Alt + F11。
Excel VBA 编辑器
Excel VBA 编辑器打开后如下所示:
Excel VBA 设置宏安全性
如果贸然运行来源不明的工作簿内的 VBA 代码,有可能导致电脑中毒。默认情况下,为防止来源不明的工作簿自带宏自动运行,Excel 会禁用宏的运行。
但是我们希望可以运行我们自己写的 VBA 代码,或者我们认为安全的其他 VBA 代码。Excel 为此提供了多种安全选项,可以做到有效防止代码自动运行,又能正确运行我们自己的代码。
宏安全性
Excel 提供 4 种宏安全性选项,在开发工具选项卡,点击「宏安全性」按钮,打开信任中心。4 种选项具体如下。
禁用所有宏,并且不通知:无法运行打开的工作簿内的 VBA 代码,Excel 也不会提示工作簿包含代码。
禁用所有宏,并发出通知:默认状态下,无法运行 VBA 代码。但是 Excel 在打开包含 VBA 代码的工作簿时,在编辑栏上方,显示安全警告,并且可以选择启用代码运行或不启用。如果选择启用,下次打开相同的工作簿,不会出现警告。
禁用无数字签署的所有宏:宏将被禁用,但如果存在宏,则会显示安全警告。但是,如果受信任发布者对宏进行了数字签名,并且您已经信任该发布者,则可运行该宏。如果您尚未信任该发布者,则会通知您启用签署的宏并信任该发布者。
启用所有宏(不推荐;可能会运行有潜在危险的代码):可以运行所有宏。一般不推荐选择此选项。
宏安全性建议策略
在实际 Excel VBA 开发过程中,我们即希望禁止来源不明的代码,又希望我们自己的代码不提示安全警告。懒人Excel 建议采取如下的安全性策略:
禁用所有宏,并发出通知。
在电脑上创建一个用于存放信任的包含代码的工作簿的文件夹,将此工作簿添加到受信任为位置。
禁用所有宏,并发出通知
在开发工具选项卡,点击「宏安全性」按钮,在宏设置里选择「禁用所有宏,并发出通知」。
添加受信任位置
把一个文件夹添加到 Excel 受信任的位置后,该文件夹下的包含 VBA 代码的工作簿打开时,不会提示安全警告,也无需每次手动开启代码。
设置方法:在开发工具选项卡,点击「宏安全性」按钮,弹出信任中心窗口,在左侧列表中,选择「受信任位置」。点击下方的「添加新位置」按钮,添加自己信任的一个文件夹。
Excel 保存包含 VBA 代码的工作簿
2003 及之前的版本中,在 xls类型工作簿可以任意编写并保存 VBA 代码。
2007 版本开始,第一次保存包含 VBA 代码的工作簿时,Excel 会提示“无法保存工作簿”。
这是因为,含 VBA 代码的工作簿,必须保存成启用宏的工作簿类型。Excel 为此提供了xlsm类型的工作簿,称之为「启用宏的工作簿」。
保存启用宏的工作簿
第一次保存时,将弹出前述提示框,为了保存 VBA 代码,其中选择「否」。在另存为窗口,保存类型列表中,选择「Excel 启用宏的工作簿(*.xlsm)」。
选择后保存,可以看到工作簿类型,xlsm。
使用 VBA 编辑器进行 Excel VBA 开发
工欲善其事,必先利其器。对于 Excel VBA 开发来说,VBA 编辑器就是最核心的开发工具。可以说,Excel VBA 开发中的每一个步骤,几乎都在 VBA 编辑器中进行,包括编写、调试、测试、运行、代码组织等。
认识 VBA 编辑器
打开编辑器,将会看到如下界面。图中已标出编辑器每个模块的名称。
编辑器中每个模块的基本用法如下:
工具栏:编辑器命令栏,与 Excel 功能区域类似,包含 Excel VBA 开发相关的命令。
VBA 工程:显示当前 VBA 工程包含的所有对象。通常,一个工作簿就是一个 VBA 工程,其中包括 Excel 对象、工作表对象、模块等。
属性窗口:查看和设置选中对象的属性的窗口。
代码编辑窗口:实际编写代码的位置。编写、修改、保存代码,都在这里进行。
立即窗口:代码运行过程中,打印出的内容,在立即窗口中显示。一般用于调试代码。
管理 VBA 工程
通常,一个工作簿就是一个 VBA 工程,其中包括 Excel 对象、工作表对象、模块等。当多个工作簿同时打开时,他们公用同一个 VBA 编辑器,VBA 工程界面显示所有的 VBA 工程。
插入/删除模块
在一个 VBA 工程中想要插入新的模块时,可在 VBA 工程右键,选择插入类型即可。
要删除模块,选中模块,右键,选择「移除 模块」
修改对象/模块属性
当点击 VBA 工程界面中任意一个 Excel 对象或模块时,在下方的属性窗口显示选中对象的各项属性信息。其中左侧是属性名,右侧是属性值,在这里可以直接手动修改属性值。
以下为一个 Excel 工作表对象的属性窗口。
运行 VBA 代码
编辑器中运行 VBA 代码,可能是执行最频繁的操作了。在开发过程中,每更新一次代码,可能需要运行,看一下其结果是否正确。
现在在模块1中有以下一段代码(如何写 VBA 代码,将在下一节中介绍):
Sub MyCode()
Sheet1.Range("A1") = "Hello World"
End Sub
代码的作用是,在 Sheet1 工作表 A1 单元格,写入 “Hello World” 内容。
在编辑器中运行 VBA 代码,有以下 3 种方法:
1.使用工具栏命令
首选,将光标放置在要运行的代码的任意一处,再在工具栏选择「运行」→「运行子过程/用户窗体」命令。
2.使用快捷工具栏命令
首选,将光标放置在要运行的代码的任意一处,再点击快捷工具栏「▶ 」按钮。
3.使用快捷键 F5
首选,将光标放置在要运行的代码的任意一处,再使用快捷键 F5,即可运行代码。
按方法2运行代码效果如下:
VBA 变量、类型、运算符
VBA 变量基础教程
本节我们学习 VBA 最基本的一个概念,VBA 变量。
什么是 VBA 变量
VBA 变量是一个存储数据的 VBA 代码结构。变量存储的数据,可在程序运行过程中改变。又能代表它存储的数据,在程序中参与各类计算。
变量可以简单理解为 Excel 中的单元格引用地址,例如 A1。在公式中,A1 代表 A1 单元格内的数据,参与计算。
变量有两个重要的概念,变量名和变量类型。
变量名:代表变量的名称
变量类型:变量存储的数据的类型,例如数字、文本、逻辑值等。
声明变量
如果想在代码中使用变量,需要先声明,即给出变量名和变量类型。
声明变量使用以下语法:
Dim [变量名] As [数据类型]
Dim和As是 VBA 中声明变量需要使用的关键词。Dim表示声明语句的开始,As表示在它之后指定数据类型。
[变量名]和[数据]是,声明代码中可变部分,需要用户输入。
[变量名] 就是该变量的名称
[数据类型] 是该变量的数据类型
声明变量实例
我们看一个实际的例子,现在声明两个变量,一个是员工姓名、一个是员工年龄。
Dim name As String
Dim age As Integer
可以看到,name和age是变量的名称,String是文本类型数据,代表员工姓名;Integer是整数数据类型,代表员工年龄。
命名变量
上述部分我们学到了声明变量的基本语句,其中变量名是需要用户自己输入。VBA 中规定,变量命名需要符合以下条件,否则程序出错。
首字母必须以字母开头。
不能包含空格、.(英文句号)、!(感叹号)、@、&、$、# 等字符。
长度不能超过 255 个字符。
不能使用 VBA 中保存的关键词作为变量名。
以上是变量名必须符合的规则。符合规则的前提下,虽然可以随便命名,但在实际开发过程,建议按驼峰法命名。
驼峰法是一种很多编程语言通用的命名规则,优点是可读性高、易于理解。
骆驼式命名法就是当变量名或函数名是由一个或多个单词连结在一起,而构成的唯一识别字时,第一个单词以小写字母开始;从第二个单词开始以后的每个单词的首字母都采用大写字母。
例如:myFirstName、myLastName,这样的变量名看上去就像骆驼峰一样此起彼伏,故得名。
变量类型
变量的第二个重要元素是变量类型,即变量存储数据的数据类型。正确指定数据类型,可以使程序编写和运行效率更高,并且易于理解。
另外,指定数据类型后,如果赋值不同类型的数据,VBA 会提示错误,这样可以避免使用错误的数据。
VBA 中的数据类型主要分为三大类,一个是数字类型,一个是非数字类型,一个是通用类型。
数字类型
数字类型的变量顾名思义,均是以数字变量。不同类型其数据范围有区别。
类型
说明
数据范围
Byte
字节
0 至 255
Integer
整数
-32,768 至 32,767
Long
长整数
-2,147,483,648 至 2,147,483,648
Single
单精度浮点数
在表示负数时: -3.402823E38 ~ -1.401298E-45 在表示正数时: 1.401298E-45 ~ 3.402823E38
Double
双精度浮点数
在表示负数时: -1.79769313486231E308 ~ -4.94065645841247E-324 在表示正数时: 4.94065645841247E-324 ~ 1.79769313486231E308
Currency
货币
-922,337,203,685,477.5808 至 922,337,203,685,477.5807
Decimal
定点数
未放置定点数: +/- 79,228,162,514,264,337,593,543,950,335 放置定点数: +/- 7.9228162514264337593543950335
非数字类型
非数字变量通常不能直接参与算术运算。
类型
说明
数据范围
String
文本类型
0 至 20亿字符
Boolean
逻辑值
True 或 False
Date
日期和时间
时间:00:00:00 至 23:59:59 日期: 100-1-1 至 9999-12-31
Object
对象
VBA 和 Excel 对象
通用类型
通用数据类型,指的是可存储任何类型的数据。在程序运行过程,VBA 可以自动识别数据类型,参与计算。
类型
说明
数据范围
Variant
任意类型
不限
Variant 类型虽然灵活,但是它会占用更多内存空间,执行效率也会受影响。因此建议,在明确知道数据是何种类型时,指定数据类型;如果数据类型是可变的或不明确,使用 Variant 类型。
给变量赋值
关于变量的基础知识学完了,接下来就是如何给变量赋值。
给变量赋值很简单,使用以下语法:
[变量名] = [数据]
赋值语法核心就是 =(等号),变量在左侧,数据在右侧。可以理解为变量等于赋值的数据。
一个值得注意的点是,[数据]的形式。
数据可以是直接书写的内容,例如 2、”学校”、True等。
也可以是另外一个变量
给变量赋值完成后,在后续的程序中,就可以使用变量参与各类计算。
我们看一下具体的例子。
Dim name As String
name = "张三"
Range("A1") = name
以上代码,先声明了 name变量,数据类型为文本。然后给它赋值了张三文本。最后将name变量的数据,写入到工作表 A1 单元格。
VBA 常量基础教程
VBA 常量是相对于VBA 变量的概念。不同于变量,常量一旦赋值,其值不能改变。在程序运行整个过程,其值一直保持不变,如果强行赋值新的数据,VBA 会报错。
使用VBA 常量,可以使一个值用更加简便的方式表达,提高编程效率。例如,使用Pi代表”3.14159…”,在代码里直接使用Pi代表 π 值。
声明常量
声明常量与声明变量类似,需要指明名称和数据类型。不同点在于,常量的值在声明时就需要指定。
声明常量的语法如下:
Const [常量名] As [数据类型] = [值]
其中,Const 是英文单词 Constant 的缩写,表示常量。
命名常量
与变量相同,常量命名需要符合以下条件,否则程序出错。
首字母必须以字母开头。
不能包含空格、.(英文句号)、!(感叹号)、@、&、$、# 等字符。
长度不能超过 255 个字符。
不能使用 VBA 中保存的关键词作为常量名。
常量类型
常量类型与变量类型相同,具体信息参考变量部分。
实例
现在看一个实例,将 π 的值作为一个常量声明,在后续的过程中,直接使用 Pi 作为 π 的值参与计算。
Sub MyCode()
'声明 π 常量
Const Pi As Double = 3.14159
'声明半径 r 和周长 C 变量
Dim r As Double
Dim C As Double
'从单元格 A1 读取半径值
r = Range("A1").Value
'计算周长
C = 2 * Pi * r
MsgBox "周长为:" & C
End Sub
看一下结果:
VBA 运算符基础教程
使用 VBA 开发某项功能,本质上是,对变量行基础的运算和操作,例如加减乘除比较等。为此,VBA 提供了很多运算符和操作符,利用它们可以实现复杂的运算。
VBA 运算符可以分为以下 6 类:
赋值运算符
算术运算符
比较运算符
逻辑运算符
连接运算符
其他运算符
赋值运算符
首先是最基础的,赋值运算符 ( = )。在 VBA 变量一文中介绍,赋值语法核心就是 =(等号),变量在左侧,数据在右侧。可以理解为变量等于赋值的数据。
运算符
说明
示例
=
给变量赋值
name = “Zhang San”
算术运算符
算数运算符是我们常用的数学运算符,包括加减乘除等。VBA 中完整的算术运算符如下。
假设 a = 10,b = 3,-> 表示结果。
运算符
说明
示例
+
两数相加
a + b -> 13
–
两数相减
a – b -> 7
*
两数相乘
a * b -> 30
/
两数相除
a / b -> 3.33…
\
两数相除,取整数部分
a \ b -> 3
Mod
两数相除,取余数
a Mod b -> 1
^
幂运算
a ^ b -> 1000
-(取负)
对数字取负
-a -> -10
比较运算符
比较运算符,比较提供的两个变量,如果符合比较条件,返回 True,否则,返回 False。
假设 a = 10,b = 3,-> 表示结果。
运算符
说明
示例
=
比较两个值是否相等
a = b -> False
>
大于
a > b -> True
>=
大于等于
a >= b -> True
<
小于
a < b -> False
<=
小于等于
a <= b -> False
<>
不等于
a <> b -> True
逻辑运算符
逻辑运算符对逻辑值,即 True 和 False,进行逻辑运算,返回运算结果,运算结果也是逻辑值。
假设 a = True,b = False,-> 表示结果。
运算符
说明
示例
And
逻辑与,两个表达式都是真,返回 True。
a And b -> False
Or
逻辑或,两个表达式至少有一个为真,返回 True。
a Or b -> True
Not
逻辑否,对逻辑表达式取否
Not a -> False
Xor
逻辑异或,如果两个表达式不相同,返回 True
a Xor b -> True
连接操作符
VBA 中的连接运算符用于连接 2 个或多个文本。其用法与 Excel 公式中的 & 符号相同。
运算符
说明
示例
&
连接两个文本
“Zhang” & ” ” & “San” -> “Zhang San”
其他操作符
运算符
说明
_ (下划线)
将一行代码分解成两行
: ( 英文冒号)
将两行代码放置在一行
VBA 数据类型基础教程
文本类型
文本类型可以说是最常用的数据类型。实际中,几乎所有的数据均是文本类型。因此理解好文本是学习 VBA 的基础。
类型
说明
数据范围
String
文本类型
0 至 20亿字符
首先,声明一个文本类型变量,String是类型标识符,语法如下:
Dim name As String
VBA 中,文本需使用英文双引号表示。
name = "Zhang San"
如果把数字两端加上双引号,它会变成文本类型,不再表示数字
name = "101"
可以使用单元格内的文本,给文本类型变量赋值。
name = Range("A1")
与 Excel 提供的文本函数一样,VBA 也提供多种文本函数,可直接在程序中使用,包括:
Format:格式化数据,并以文本类型返回
InStr:返回指定字符的位置
InStrRev:反方向返回指定字符位置
Left:返回左侧指定长度文本
Len:返回文本长度
LCase:大写字母转换成小写字母
LTrim:清除开头的空格
Mid:返回指定的开始和结束位置之间的文本
Replace:替换文本中的指定字符
Right:返回右侧指定长度文本
RTrim:清除末尾处的空格
Space:返回指定重复数的空格文本
StrComp:返回比较两个文本的结果
StrConv:将文本转换成指定格式
String:返回指定重复数的文本
StrReverse:逆转提供的字符串
Trim:清除开头和结尾处的空格
UCase:将小写字母转换成大写字母
每个函数的用法,在「内置函数」一章中详细介绍。
数字类型
数字类型是第二个基础数据类型。在写 VBA 代码时,应根据具体的数字大小,选择合适的数字类型。
如果小数字使用大范围数字类型存储,会浪费计算机内存;如果大数字使用小范围的数字类型存储,VBA 会自动转换成对应小范围数字,导致数字丢失精度。
VBA 中的数字类型包括如下几种。
类型
说明
数据范围
Byte
字节
0 至 255
Integer
整数
-32,768 至 32,767
Long
长整数
-2,147,483,648 至 2,147,483,648
Single
单精度浮点数
在表示负数时: -3.402823E38 ~ -1.401298E-45 在表示正数时: 1.401298E-45 ~ 3.402823E38
Double
双精度浮点数
在表示负数时: -1.79769313486231E308 ~ -4.94065645841247E-324 在表示正数时: 4.94065645841247E-324 ~ 1.79769313486231E308
Currency
货币
-922,337,203,685,477.5808 至 922,337,203,685,477.5807
Decimal
定点数
未放置定点数: +/- 79,228,162,514,264,337,593,543,950,335 放置定点数: +/- 7.9228162514264337593543950335
其中,Integer、Long、Double是常用到的数字类型。
与文本相似,声明数字类型,使用如下语句:
Dim age As Integer
以上定义一个岁数变量,使用基本的 Integer 整数类型即可。
数字类型变量可以像数字一样,参与各类算数运算:
age = 3
age * 2 + 10 ‘-> 16
更多数字类型相关的内容,将在以后的教程中详细介绍。
逻辑类型
逻辑类型只有两个值,True 和 False,即真与假。
类型
说明
数据范围
Boolean
逻辑值
True 或 False
逻辑值虽然只有两个,但是在程序中有着广泛的应用。VBA 中判断语句中,经常能用到逻辑值。
首选,声明一个逻辑变量,使用如下语句:
Dim isPass As Boolean
给逻辑变量赋值时,可以直接使用逻辑值,也可以使用返回逻辑值的表达式。
isPass = False
isPass = 70 >= 60
日期和时间类型
VBA 中的日期和时间使用数字表示,整数部分代表日期,小数部分代表时间。
日期从 100-1-1 开始到 9999-12-31。
时间从 00:00:00 到 23:59:59。
声明日期类型变量,使用如下语句:
Dim birthday As Date
Dim time As Date
给日期变量赋值时,可以直接把日期放置在两个 # 之间赋值,也可以使用数字,还可以把日期作为文本赋值:
birthday = #2018-1-1#
birthday = 43101
birthday = "2018-1-1"
time = #12:00:00#
time = 0.5
time = "12:00:00"
Variant 类型
Variant 类型是一种通用类型,可以表示任何一种类型的数据。它也是声明变量未指定数据类型时的默认类型。
虽然 Variant 类型方便,但是相应的,占用更大的内存空间,也会影响程序运行效率。因此建议,在明确知道数据时何种类型时,指定数据类型;如果数据类型是可变的或不明确,使用 Variant 类型。
VBA 程序结构
VBA 程序结构入门
从本节开始,我们进入 VBA 语法的另外一个重要概念,程序结构。
上一节学习的变量、数据类型、运算符等概念,是 VBA 中"静态"的部分。相对的,程序结构是 VBA 中 "动态" 的部分。学习完程序结构,才能真正写出可以运行的 VBA 程序。
本节我们先介绍程序结构最常用的部分,深入学习前有一个基本概念。本节余下的教程中,将详细介绍每一个程序结构。
程序结构示例
首先,本节将使用以下代码,介绍各种程序结构,大家可以先看一下。
Sub MyCode()
'声明循环变量和是否为空变量
Dim i As Integer
Dim isBlank As Boolean
'循环 A2-A10 单元格
For i = 2 To 10
'存储单元格是否为空的结果
isBlank = Cells(i, 1).Value = ""
'如果为空,则用上方的单元格的值填充当前单元格
If isBlank Then
Cells(i, 1) = Cells(i - 1, 1)
End If
Next i
End Sub
以上代码运行后,在 A2:A10 单元格区域,依次判断每一个单元格是否为空,如果是空,则用上一个单元格的值填充。
过程
过程是 VBA 中,程序实际运行的最小结构。单独的一行或多行代码无法运行,必须把它们放置在一个过程里,才能运行。
在示例中,Sub 过程名() 开头,End Sub 为结尾部分是一个过程的主体,其余代码需要放置在两者之间。
Sub MyCode()
End Sub
程序语句
语句,是表示一个完整意思的一行代码。
例如,示例中第一行,声明变量就是一条语句。它表示,声明一个整型变量。同理,第二行、第三行和其余的每一行都是语句。VBA 中的过程,就是由这样一条条语句构成的。
Dim i As Integer
Dim isBlank As Boolean
通常,一行就是一个语句,除非它用换行符或合并符号。
Excel VBA 对象
我们学习 VBA 的最终目的是操纵 Excel,完成一些特定的目标。其中,操纵 Excel 就是通过 Excel VBA 对象完成的。
在示例中,Cells() 就是一个 Excel VBA 对象,表示一个单元格,提供行号和列号指定单元格。
程序运行结构
接下来是程序结构中最核心的部分,也是最有意思的部分,程序运行结构。大部分编程语言都具备基本的三种程序运行结构,分别是顺序结构、循环结构、判断结构。各种简单到复杂的算法,都是由这三种基本的结构,相互组合而完成。
1.顺序结构
首先是基本的顺序结构。顺序结构,顾名思义就是按照顺序依次执行。VBA 中的顺序就是从上到下、从左到右的顺序。
在示例中,首先运行两个声明语句,然后运行循环结构,以此类推。值得注意的是,当程序有嵌套时,嵌套的部分也是按照顺序执行的。
2.循环结构
第二个基本结构是循环结构。当使用循环结构时,循环部分代码,按照指定的循环次数,循环重复执行。
在我们的示例中,For 至 Next i 之间的代码就是一个循环代码。
VBA 中,有多种循环结构,本例中是 For 循环结构。For 循环结构中,第一行指定循环次数,最后一行表示开始下一个循环。
'循环开始
For i = 2 To 10
'这里是循环的代码
Next i
3.判断结构
最后一种基本结构是,判断结构。简单来说,该结构中,当提供的表达式为真(True)时,判断结构的主体部分才会被执行,否则跳过。
在示例代码中,If 开头和 End If 结尾处是典型的判断结构。第一行,判断 isBlank 变量是否为真,如果是,则执行判断结构主体部分,否则跳过。
'如果为空,则用上方的单元格的值填充当前单元格
If isBlank Then
Cells(i, 1) = Cells(i - 1, 1)
End If
注释
通常,一段代码写完后,不会完全没问题。在实际使用过程中可能需要修改,符合最新的需求。过一段时间再打开查看时,可能已经忘记了当时的思路,不能很快想起来有些代码实际的用途,更不用说让别人查看了。这时,就需要注释出场了。
注释是对代码的一种解释,不影响代码的运行。VBA 中的注释语句是,以英文单引号 (')开头,后接需要解释说明的内容。
注释可以让代码更容易理解,建议从一开始就养成写注释的习惯。
运行
下面,我们实际运行我们的示例代码,看一看它具体的效果。
VBA 表达式和语句
表达式
首先,相比语句更小的一种代码结构是,表达式。按照字面意思,可以分为两部分,表达和式。组合起来是,通过一种式子,表达相应的值。
VBA 中,返回一个值的代码片段,称之为表达式。
最简单的,最基本的数据写出来就是一个表达式,它返回的是自己本身(100、”Excel” 等)。
100 '=> 100
"Hello World" '=> Hello World
True '=> True
#2018-11-1# '=>2018-11-1
表达式也可以是,多个数据之间的运算表达式。例如,算数运算、逻辑运算、连接运算等。
1+2 '=> 3
10 > 5 '=> True
"Hello " & "World" '=> Hello World
进一步,表达式可以是多个表达式之间的运算。这种时候,往往会把多个表达式用()括起来,保证运算顺序。
Not (10 > 5) '=> False
(1 + 2) - (10 - 5) '=> -2
使用 VBA 函数也可以是表达式,例如 Left 函数返回左侧指定长度文本。
Left("Hello World", 5) '=> Hello
Abs(-10) '=> 10
Year(#2018-11-1#) '=> 2018
当然,最重要的,表达式中能使用变量。
Dim place As String
place = "World"
"Hello" & place '=> Hello World
Left(place, 3) '=> Wor
语句
编程中光有表达式没有办法做成什么事,需要把表达式与其他元素组合成一个语句,才能发挥它的作用。
VBA 中,一条语句是一个完整指令的。它可以包含关键词、运算符、变量、常量以及表达式。
语句有三大类,分别是:
声明式语句,也就是声明变量、常量、过程或者函数。
执行式语句,执行指定动作。动作可以包括执行一个过程、开始一个循环、判断表达式等。
赋值语句,给变量赋值,是执行式语句的特殊形式。
接下来,分别介绍三类语句。
1.声明式语句
声明式语句用来声明一个新的变量(包括类型),过程、函数、对象、数组等。
我们看以下代码。
Sub MyCode()
Dim name As String
Dim age As Integer
End Sub
这段代码中,第一个语句就是第一行,声明一个 VBA 过程。声明过程以 Sub开头,后接过程名()。对应的,最后一行是,过程的结束语句,即 End Sub
接下来是,两个声明变量的语句,name 和 age,并且语句中指定了他们的类型。
2.执行式语句
执行式语句执行一个动作。这个动作可以是运行过程、开始循环、判断表达式等。
我们以一个判断语句为例,看一下代码。
Sub MyCode()
Dim name As String
Dim age As Integer
name = "Zhang San"
age = 28
If age > 25 then
MsgBox name & " 岁数超过25了。"
End If
End Sub
这段代码中,If 语句判断 age 变量是否大于 25,如果是,则运行与 End If之间的代码,否则跳过不运行。这其中的If ... End If 就是一个执行式语句。
这种执行式语句是 VBA 语法中的最重要的部分,在接下来的学习中,将详细介绍。
3.赋值语句
赋值语句,顾名思义给变量赋值。它是执行式语句的一种特殊形式。
赋值语句的核心是 =,左侧是变量,右侧是赋的值。
我还是看上述代码,这次我们加上赋值语句。
Sub MyCode()
Dim name As String
Dim age As Integer
name = "Zhang San"
age = 28
End Sub
显然,name = "Zhang San"和age = 28是赋值语句。
另外值得注意的是,VBA 中的变量可以重复赋值,其值等于最后一次赋的值。这在实际的 VBA 开发中十分有用。
书写语句的 2 个技巧
在运算符一文中,简单说了 2 个运算符,一个是英文冒号(😃,一个是下划线(_)。
运算符
说明
: ( 英文冒号)
将两行代码放置在一行
_ (下划线)
将一行代码分解成两行
: ( 英文冒号)
通常,VBA 中直接将多个语句放置在一行,VBA 会报错。如果想要放置在一行,需要用 : ( 英文冒号)连接多个语句。
Sub MyCode()
Dim name As String : Dim age As Integer
End Sub
_ (下划线)
相反,当一条语句过长时,可能需要分成多行书写。如果把一条语句直接回车分成多行,VBA 也会报错。这时需要把空格 + _放置在换行处。
Sub MyCode()
Dim name As String
name = "Hello" & _
"World"
End Sub
VBA 变量的声明和赋值
什么是声明变量
变量是一个存储数据的 VBA 代码结构。在代码中,通过变量名获取变量所代表的值。而声明变量,就是告诉 VBA,变量的名字和它所存储的值的数据类型。
VBA 中声明变量,有 4 种变量,它们是:
基本类型变量。基本类型变量是那些存储单个数据的变量,例如数字、文本、日期等。
通用变量。通用变量,即 Variant 类型变量。该变量的类型在程序运行过程中,根据赋值的数据自动指定。
数组。数组包含多个变量的集合。
对象。对象包含一些列属性和方法。
声明语句的基本语法
4 种类型的变量的声明方法基本一致。他们的语法如下。
1.基本类型变量
'语法
Dim [变量名] As [数据类型]
'实例
Dim name As String
Dim age As Integer
Dim height As Double
Dim birthday As Date
2.通用变量
声明 Variant 类型变量时,如果忽略数据类型,默认情况是 Variant 类型,因此下方两种方式是相同的。
'语法
Dim [变量名] As Variant
Dim [变量名]
'实例
Dim message As Variant
Dim message
3.数组
'语法
'固定长度数组声明
Dim [变量名](开始序号 to 结束序号) As [数据类型]
'动态数组声明
Dim [变量名]() As [数据类型]
'实例
'声明包含10个文本类型元素的数组
Dim names(1 to 10) As String
'声明长度未知的文本类型数组
Dim names() As String
关于数组的声明和赋值,将在数组一章中做详细的介绍。
4.对象
声明对象时,一般有两种方式。一种是前期绑定,即一开始就指定对象的类型;一种是后期绑定,即声明时不指定对象类型,后期指定。
'语法
'前期绑定声明语法
Dim [变量名] As [对象类型]
'后期绑定声明语法
Dim [变量名] As Object
'实例
Dim sh As Worksheet
Dim car As Object
关于对象的声明和赋值,在对象一章中做更详细的介绍。
在哪里写声明语句
声明变量,意思是在使用变量前,告诉 VBA,变量的名字和数据类型。因此,声明变量的语句,必须写在使用它的语句前。
错误写法
如果先于声明语句前使用变量,VBA 会报「变量未定义」错误。
正确写法
Dim name As String
name = "Zhang San"
如何声明多个同类型变量
通过以上部分的学习,在写多个同类型变量的声明语句时,有人可能会按以下方式写:
'声明两个整数类型的 i、j 变量
Dim i,j As Integer
首先,以上写法,语法上没问题,不会出现错误。但是,这种方式声明变量,Integer 类型只作为第二个 j 变量的数据类型。第一个变量,即 i 变量,它的数据类型是 Variant,并不是 Integer 类型。
因此,VBA 中不能合并声明语句。正确的声明方法如下:
'第一种,按两行写
Dim i As Integer
Dim j As Integer
'第二种,使用 : 符号,在一行写
Dim i As Integer : Dim j As Integer
声明变量是必须的吗
准确来讲,VBA 中声明变量不是必须的。也就是说,没有声明变量,而直接开始用,也没有错误。
但是,不声明变量,是一种不好的习惯,也常常会带来很多错误。这也是为什么之前的教程中都没有提到这点的原因。
不声明变量典型弊端包括:
数据类型自动设置为 Variant 类型,效率低。
变量名写错,不会提示错误。
无法使用 VBA 代码自动补全。
数据类型不匹配时,不会提示错误。
基于以上原因,强烈建议,每次使用变量,都要声明其变量名和数据类型。
VBA 提供一个选项,可以强制变量声明,即在模块头部写上以下语句:
Option Explicit
模块中有以上语句时,如果未声明变量而直接使用变量,VBA 会提示「变量未定义」错误,方便检查代码。
设置 VBA 编辑器变量声明选项时,可以自动为每个模块插入Option Explicit语句,不需要手动书写。设置方法如下:
基本类型变量的赋值
基本类型变量是存储单个值的变量,例如数字、文本、日期等。
VBA 中,给基本类型变量赋值,以 Let关键词开头。赋值操作是给=左侧的变量,用=右边的数据,指定其代表的值。在后续的代码中,该变量就代表指定的数据。
在实际开发中,给基本类型变量赋值时,Let关键词可以忽略不写,直接以变量开头写赋值语句。
给基本类型变量赋值语法如下:
'语法,两种写法相同
Let [变量名] = [数据]
[变量名] = [数据]
'实例
Dim name As String
Let name = "Zhang San"
Dim age As Integer
Let age = 30
Dim birthday As Date
Let birthday = #2000-1-1#
赋值语句中,=右侧可以是包含其他变量、函数、复杂计算的表达式。该表达式返回的值的类型,与变量类型一致就可以正常赋值。
Dim birthday As Date
Dim age As Integer
birthday = #2000-1-1#
age = Year(Now) - Year(birthday)
一种特殊情况是,=右侧可以是变量本身。这种方式多用于循环结构中。
Dim i As Integer
Do While i < 10
Msgbox i
i = i + 1
Loop
'返回 => 0,1,2,3,4,5,6,7,8,9
Variant 类型变量的赋值
我们知道 Variant 类型时通用类型,因此赋值很直接,没有类型强制要求。Variant 类型变量第一次赋值后,可以继续赋值其他类型数据。
'声明变量(两者相同)
Dim message As Variant
Dim message
'赋值
message = "Hello World"
message = 1234567890
message = #2018-12-1#
这里依然强调,虽然 Variant 类型变量比较灵活,但是也有很多弊端,所以在实际开发中,不建议使用该类型,使用确切类型变量。
数组类型变量的赋值
数组是可以存储多个同类型元素的数据类型。声明时一般指定其数据长度。给数组赋值时,一般使用每个元素的序号。
数组赋值基本语法如下:
[数组名](元素序号) = [数据]
下面看一下实际的实例。
'声明数组
Dim arr(1 to 5) As String
'数组赋值
arr(1) = "Zhang San"
arr(2) = "Li Si"
arr(3) = "Wang Wu"
以上是数组的基本赋值方式,关于数组的更多声明和赋值方法,将在《数组》一章中详细介绍。
对象类型变量的赋值
VBA 中,对象是程序的一个元素,不同于基本类型数据,它包括多个属性和多个方法。例如,Excel 中工作簿、工作表、单元格、图表等都是对象。
对象类型变量赋值时,不同于基本类型变量使用Let(可以忽略)关键词,对象使用 Set 关键词,并且Set关键词不能省略。
如下是对象类型变量基本的赋值方法:
Set [变量名] = [对象类型数据]
下面看一下实际的用法。
'声明工作表类型的对象
Dim sheet As Worksheet
'将名称为“绩效表”的工作表,赋到 sheet 变量
Set sheet = Worksheets("绩效表")
由于对象可以包含多个属性,因此 VBA 提供一种同时给多个属性赋值的简单方法。具体方法是对象多个属性赋值语句,放置在 With+对象和End With关键词中间。
Dim sheet As Worksheet
Set sheet = Worksheets("绩效表")
With sheet
.Name = "旧绩效"
.Visible = False
End With
VBA 程序顺序结构
程序结构中最核心的部分,程序运行结构。
大部分编程语言都具备基本的三种程序运行结构,分别是顺序结构、循环结构、判断结构。各种简单到复杂的算法,都是由这三种基本的结构,相互组合而完成。
顺序结构执行方式
顺序结构,顾名思义就是按照一定的顺序依次执行。VBA 中的执行顺序就是,从左到右、从上到下的顺序。
如下代码运行后,按照上述顺序,依次打印出对应的内容。其中,Debug.Print函数是 VBA 内置函数,用于在立即窗口打印显示指定的内容。
嵌套过程和函数执行方式
实际开发中,为了组织代码,会出现在一个过程中,使用其他过程或函数的情形。这种情形与 Excel 中嵌套函数类似。
程序运行到子过程或函数时,按照顺序执行原则,先运行子过程或函数,再继续运行剩余的代码。子过程或函数的执行顺序,依然是顺序执行。
如下代码运行后,按照上述顺序,依次打印出对应的内容。其中 Call关键词用于执行一个过程或函数。
VBA 程序选择结构
VBA 程序执行三大结构中,选择结构(判断)用于选择性地执行代码。选择结构与 Excel 的 IF 函数类似,也是以 IF 为关键词,按照判断条件的真假,执行不同的操作。但是 VBA 中的 IF比 Excel 中的 IF 函数更强大。
选择结构基础
选择结构,根据提供的条件表达式的值,如果为真(True),则执行选择结构的主体代码,否则跳过。
选择结构的核心是判断条件表达式的真假,这一步理解了,也就理解了选择结构的多种形式。
选择结构的基本执行方式如下:
示例数据
本节我们使用一个班级的考试成绩作为示例数据。代码中如何与 Excel 中的数据交互,不需要看懂,这部分在 Excel 对象模型中详细介绍。
If Then 结构
选择结构中,If Then 结构是最基础的一个。它只有条件表达式真时,执行的代码。
If Then结构基本语法如下,其中 End If是选择结构的结束标志。
If 条件表达式 Then
'表达式为真时,执行的代码
End If
现在我们看实际的例子,判断学生是否及格,及格条件是成绩 ≥60。如果及格,在C列对应单元格填写“及格”。具体代码如下:
Sub MyCode()
Dim i As Integer
For i = 2 To 10
If Cells(i, "B").Value >= 60 Then
Cells(i, "C") = "及格"
End If
Next i
End Sub
我们可以看到,我们使用 B 列中的学生成绩与 60 分比较,如果≥60分,就在 C 列填写及格。
条件表达式是 Cells(i, "B").Value >= 60,选择性执行的代码部分是 Cells(i, "C") = "及格"。
其中,For 语句是表示循环结构,这里只需知道程序从第一个学生循环到最后一个学生,依次判断每个学生的成绩。循环结构将在下一节中做详细介绍。
将以上代码运行后,可以看到运行结果如下:
If Else 结构
很多时候,我们根据表达式的真假,真时执行一块代码,假时执行另一块代码。这种需求可以使用 If Else结构实现。
If Else结构中,条件表达式在真时,执行Then后的代码;条件表达式为假时,执行 Else后的代码。基本语法如下:
If 条件表达式 Then
'真时执行的代码
Else
'假时执行的代码
End If
我们继续看实际的例子。在上一个例子的基础上,这次对不及格的学生,在C列填入不及格。代码如下:
Sub MyCode()
Dim i As Integer
For i = 2 To 10
If Cells(i, "B").Value >= 60 Then
Cells(i, "C") = "及格"
Else
Cells(i, "C") = "不及格"
End If
Next i
End Sub
在这个例子中,条件表达式 Cells(i, "B").Value >= 60为假时,表示学生成绩低于60分,即不及格。这时就执行 Else后的代码。
程序运行结果如下:
If ElseIf Else 结构
前面两种结构中,最多有两种选择,即 ≥ 60 和 < 60。有时针对同一个变量,可能存在多种判断标准。例如,对及格的学生,继续评级及格、良和优。
选择结构中,可以使用 If ElseIf Else结构,对同一个变量进行多次判断,并且为每一个判断结果编写不同的代码块,达到执行式 n 选 1 的效果。
If ElseIf Else结构的基本语法如下:
If 条件表达式1 Then
'表达式1真时,执行的代码
ElseIf 条件表达式2 Then
'表达式2真时,执行的代码
ElseIf 条件表达式3 Then
'表达式3真时,执行的代码
...
ElseIf 条件表达式n Then
'表达式n真时,执行的代码
Else
'以上表达式都不为真时,执行的代码
End If
这种选择结构需要注意的是:
条件表达式是从第一个开始判断。
判断过程中,只要有一个表达式结果为真,那么执行对应的代码块,然后退出选择结构,不再继续判断剩下的表达式。
当所有的表达式都不为真时,执行 Else后的代码块。
根据以上规律,我们写一下判断学生成绩评级的代码。思路是,拿学生成绩,分别于85、75、60分比较,在 D 列填写对应的评级。
Sub MyCode()
Dim i As Integer
For i = 2 To 10
If Cells(i, "B").Value >= 85 Then
Cells(i, "D") = "优"
ElseIf Cells(i, "B").Value >= 75 Then
Cells(i, "D") = "良"
ElseIf Cells(i, "B").Value >= 60 Then
Cells(i, "D") = "及格"
Else
Cells(i, "D") = "不及格"
End If
Next i
End Sub
代码运行结果如下:
Select Case 结构
Select Case结构是对同一个变量进行多次判断的另一种方式。相对于If ElseIf Else结构,它把条件表达式中的变量提取出来,使得代码结构更简洁,也更易于阅读。
Select Case结构的基本语法如下:
Select Case 变量
Case 判断条件 1
'条件 1 真时,执行的代码
Case 判断条件 2
'条件 2 真时,执行的代码
Case 判断条件 3
'条件 3 真时,执行的代码
Case Else
'之前的所有条件都不为真时,执行的代码
End Select
可以看到,Select Case结构把 If结构中的条件表达式拆分了,即把变量和判断条件分开了。
我们看前一个例子,使用Select Case结构,代码如下:
Sub MyCode()
Dim i As Integer
For i = 2 To 10
Select Case Cells(i, "B").Value
Case Is >= 85
Cells(i, "D") = "优"
Case Is >= 75
Cells(i, "D") = "良"
Case Is >= 60
Cells(i, "D") = "及格"
Case Else
Cells(i, "D") = "不及格"
End Select
Next i
End Sub
这一例子中,学生成绩是变量,即 Cells(i, "B").Value,判断条件是每个 Case 语句后的条件。
代码运行结构如下:
VBA 程序循环结构
VBA 中,循环结构用于多次重复执行同一段代码。重复次数通过特定数字或特定条件控制。
通过控制循环过程中特定变量,循环结构可执行复杂的重复任务。
循环结构的执行流程可简单的表示如下:
VBA 循环结构类型
VBA 中循环结构有 3 种类型,它们是:
For 循环
Do While 循环
Do Until 循环
下面分别介绍 3 种类型循环结构语法以及用法。
For 循环
For 循环是最常用的循环类型,它有两种形式:
For … Next 循环
For Each 循环
For … Next 循环
使用 For ... Next 循环可以按指定次数,循环执行一段代码。For 循环使用一个数字变量,从初始值开始,每循环一次,变量值增加或减小,直到变量的值等于指定的结束值时,循环结束。
For ... Next 循环语法如下:
For [变量] = [初始值] To [结束值] Step [步长]
'这里是循环执行的语句
Next
其中:
[变量] 是一个数字类型变量,可在循环执行的语句里使用。
[初始值] 和 [结束值] 是给定的值;
[步长] 是每次循环时,变量的增量。如果为正值,变量增大;如果为负值,变量减小。
下面看一个实际的例子,求 1 至 10 数字的累积和。
Sub MyCode()
Dim i As Integer
Dim sum As Integer
For i = 1 To 10 Step 1
sum = sum + i
Next
End Sub
可以看到,For 循环使用 i 变量,循环 10 次,i 的值从 1 到 10 变化。
值得注意的是,For 循环的 Step 值如果是 1,则 Step 关键词可省略。上述过程循环部分可写成如下方式:
For i = 1 To 10
sum = sum + i
Next
For Each 循环
For Each 循环用于逐一遍历一个数据集合中的所有元素。数据集合包括数组、Excel 对象集合、字典等。
For Each 循环不需要一个数字变量,但是需要与数据集合中的元素相同的数据类型变量。其基本语法如下:
For Each [元素] In [元素集合]
'循环执行的代码
Next [元素]
其中,
[元素] 是与集合中的元素相同类型的变量,该变量可在循环代码中使用。
[元素集合]是包括多个元素的集合。
下面看一个实际例子,循环打印出工作簿中所有工作表的名称。
Sub MyCode()
Dim sh As Worksheet
For Each sh In Worksheets
Debug.Print sh.Name
Next sh
End Sub
sh 变量就是元素变量,Worksheets 是工作簿中所有工作表的集合。
Exit For 语句
Exit For 语句用于跳出循环过程,一般在提前结束循环时使用,均适用于 For Next 循环和 For Each 循环。
看一个实际的例子,求 1 – 10 数字的和时,当和大于 30 就停止循环。
Sub MyCode()
Dim i As Integer
Dim sum As Integer
For i = 1 To 10
sum = sum + i
If sum > 30 Then
Exit For
End If
Next
End Sub
在这段代码中,sum 变量大于 30 时,循环就停止。
Do While 循环
Do While 循环用于满足指定条件时循环执行一段代码的情形。循环的指定条件在 While 关键词后书写。
Do While 循环也有两种形式:
Do While … Loop 循环
Do … Loop While 循环
Do While … Loop 循环
Do While … Loop 循环,根据 While 关键词后的条件表达式的值,真时执行,假时停止执行。基本语法如下:
Do While [条件表达式]
'循环执行的代码
Loop
其中,只要 [条件表达式] 为真,将一直循环执行。[条件表达式] 一旦为假,则停止循环,程序执行 Loop 关键词后的代码。
看一个实际的例子,还是求 1- 10 累积和。
Sub MyCode()
Dim i As Integer
Dim sum As Integer
i = 1
Do While i <= 10
sum = sum + i
i = i + 1
Loop
End Sub
i 变量的初始值是 1,根据 While 后的条件,只要 i 变量小于等于 10,后续的代码就可以一直循环执行。
这里为了演示使用了 Do While 循环,实际情况下,这种求和问题,使用 For 循环更简洁。
Do … Loop While 循环
与上一种 Do 循环不同的是,Do ... Loop While循环至少循环执行代码一次后,再判断条件表达式的值。基本语法如下:
Do
'循环执行的代码
Loop While [条件表达式]
其中,While 和条件表达式写在 Loop 关键词后。
Exit Do 语句
与 Exit For 语句类似,Exit Do 语句用于跳出 Do While 循环。
Do Until 循环
Do Until 循环与 Do While 循环类似。不同点在于,Do While 在条件表达式为真时,继续执行循环;而 Do Until 在条件表达式为真时,停止执行循环。
Do Until 循环也有两种形式:
Do Until … Loop 循环
Do … Loop Until 循环
Do Until … Loop 循环
循环开始前判断 Until 后条件表达式的值,如果是真,停止循环;如果是假,继续执行循环。基本语法如下:
Do Until [条件表达式]
'循环执行的代码
Loop
Do … Loop Until 循环
先运行一次,再判断 Until 后条件表达式的值,如果是真,停止循环;如果是假,继续执行循环。基本语法如下:
Do
'循环执行的代码
Loop Until [条件表达式]
小结
本节我们学习了 VBA 中程序循环结构基础,以及多种循环结构形式。包括子类在内,VBA 中常使用的循环结构包括 6 种,它们是:
循环结构
说明
For … Next 循环
按指定次数循环执行
For Each 循环
逐一遍历数据集合中的每一个元素
Do While … Loop 循环
当条件为真时,循环执行
Do … Loop While 循环
当条件为真时,循环执行。无论条件真假,至少运行一次
Do Until … Loop 循环
直到条件为真时,停止执行
Do … Loop Until 循环
直到条件为真时,停止执行。无论条件真假,至少运行一次
此外,学习了两种跳出循环的语句,它们是:
跳出语句
说明
Exit For
跳出 For 循环
Exit Do
跳出 Do While/Until 循环
VBA With 结构
VBA 中,With 结构用于组合同一个对象的多个属性和方法,避免重复写同一个对象名,提高编程和运行效率。
With 结构语法
With 结构由 With 和 End With 两个语句构成,对象的属性和方法都写在两者之间。基本语法如下:
With [对象]
.[属性] = [数据]
.[方法]
'其他属性和方法
End With
With 结构里,对象的属性和方法均由点 (.)符号开始,后接对象的属性名和方法名。
With 结构实例
现在看一个实际的例子,需要将工作簿中 Sheet1 工作表设置新名称,然后设置标签颜色为黑色,最后隐藏工作表。
如果不用 With 结构,代码如下:
Sub MyCode()
Worksheets("Sheet1").Name = "新名称"
Worksheets("新名称").Tab.ThemeColor = xlThemeColorLight1
Worksheets("新名称").Visible = xlSheetHidden
End Sub
可以看到,每个语句都重复写 Worksheets("工作表名称") 部分。
使用 With 结构,可以避免重复写同一个对象名,代码如下:
Sub MyCode()
With Worksheets("Sheet1")
.Name = "新名称"
.Tab.ThemeColor = xlThemeColorLight1
.Visible = xlSheetHidden
End With
End Sub
嵌套 With 结构
With 结构还能嵌套编写,即一个 With 结构中,如果父对象的属性是另一个对象,则针对这个子对象,继续使用 With 结构。
在之前的例子中,如果需要将 Sheet1 工作表中,A1:A10 单元格区域设置背景颜色,调整字体和字体大小,可以使用如下代码:
Sub MyCode()
With Worksheets("Sheet1")
.Name = "新名称"
.Tab.ThemeColor = xlThemeColorLight1
.Visible = xlSheetHidden
With .Range("A1:A10")
.Interior.ThemeColor = xlThemeColorAccent1
.Font.Size = 12
.Font.Name = "等线"
End With
End With
End Sub
VBA GoTo 结构
VBA 中,在程序运行时,使用 GoTo 结构,跳转到指定标签处运行,从而不执行 GoTo 语句和指定标签之间的代码。
在实际的 VBA 开发中,Goto 结构多用于处理错误的情形,即发生错误时,跳转到处理错误的代码处。
语法
GoTo 结构由 GoTo 语句和标签语句组成。基本语法如下:
GoTo [标签]
'被跳过的代码
...
[标签]:
'被执行的代码
跳转的位置由 Goto 关键词后的 [标签] 告诉程序,VBA 会在代码中查找对应的 [标签]: 关键词,从标签下一行继续执行程序。
需要注意的是,跳转处的标签,后接冒号 ( : ) 。
实例
下面的例子说明 GoTo 结构的基本用法。使用 VBA 作除法,如果除数是零,则跳转到程序末尾,提示除数不符合规范。
Sub MyCode()
Dim num1 As Double
Dim num2 As Double
Dim result As Double
num1 = 100
num2 = 0
If num2 = 0 Then GoTo error
result = num1 / num2
Exit Sub
error:
MsgBox "除数不能为零"
End Sub
可以看到,例子中 num2 是除数,程序判断 num2 是否为零,如果是,则跳转到 Error 标签处,除法部分不会被执行。
小结
Goto 结构相对简单,实际开发中不像三大结构使用频繁,但是在一些情形中使用,可以使代码更简洁易读。GoTo 语句常用于错误处理外,还可以用在「上一步/下一步」类情形中,根据用户需求,重复执行同一个步骤,这方面内容在以后做更多介绍。
VBA 注释教程和实例
VBA 中,注释是对程序作出的说明。VBA 代码运行时,会跳过注释语句,因此注释不影响代码的运行。
如何写注释
VBA 中的注释语句是,以英文单引号 (')开头,后接需要解释说明的内容。基本语法如下:
'注释的内容
我们看实际的例子。
注释可以写在一行,单引号后的内容均是注释的内容。
Sub MyCode()
'定义姓名变量
Dim name As String
End Sub
注释也可以在一行代码的结尾,同样,单引号后的内容均是注释的内容。
Sub MyCode()
'定义姓名变量
Dim name As String
name = Range("A1").Value '从A1单元格读取姓名
End Sub
注释内容是多行内容,需要在每一行开头使用单引号。
'此过程用于读取 A1 单元格的值
'最后更新于 2018-12-13
'作者 懒人Excel
Sub MyCode()
'定义姓名变量
Dim name As String
name = Range("A1").Value '从A1单元格读取姓名
End Sub
注释的用途
最基本的用途当然是对代码标注说明,例如:
提供过程或函数的基本信息、用途;
说明变量的用途;
解释为什么使用当前的方法;
区分开不同代码块
注释另一个常见的用法是,在开发调试过程中,临时注释一段代码,使其不被执行,检查代码其余部分是否有错误。
VBA 过程和函数 (Sub | Function)
VBA 过程(Sub)
VBA 中,过程是一切的开始,几乎所有的代码,都会被写在一个或多个过程里。
实际开发中,通常一个过程,建议只完成一个特定的小目标。因此,我们的程序往往会包含多个过程。这就是 VBA 中过程概念存在的一个原因。
程序中使用过程,可以使程序更简洁、清晰,开发中大型项目更易于管理代码。
过程基础语法
VBA 过程以 Sub 语句开始,以 End Sub 语句结束,包含一个或多个语句,完成一个特定的目标。
无参数过程
无参数的 VBA 过程的基本语法如下:
Sub [过程名]()
语句1
语句2
...
语句n
End Sub
可以看到,过程以 Sub 语句开始,以 End Sub 语句结束,并且具备一个名称,名称后有括号 ()。
我们看一个简单的例子。
Sub SayHello()
Msgbox "Hello World"
End Sub
上述就是一个简单的过程,过程名是 SayHello。这个过程只包含一个语句,运行时,弹出对话框显示 Hello World。
有参数过程
过程还可以接受一个或多个参数,参数可以是常量、变量、表达式,并且每个参数指定其名称。在过程的语句中,接受的参数,以名称指定方式被使用。
接受参数的过程基本语法如下:
Sub [过程名]([变量名1] As [数据类型1],...[变量名n] As [数据类型n])
语句1
语句2
...
语句n
End Sub
与无参数过程相比,有参数过程在过程名后的括号 () 中,包含一个或多个参数。参数的写法与声明变量语句类似,不同点是在这里不用写 Dim。
[变量名1] As [数据类型1]
我们看一个例子。
'声明一个过程
Sub SayHello(name As String)
Msgbox "Hello" & name
End Sub
'在另一个过程,调用上述过程,调用时,提供一个实际的 name 参数
Sub MyCode()
SayHello "World 2"
End Sub
我们在运行 MyCode 过程时,提供了 name 变量,即 World 2 ,运行时弹出对话框显示 Hello World 2。
调用子过程(Sub)
在程序开发中,把代码拆分成多个子过程和函数,可以使项目更容易管理、测试和运行,VBA 中也不例外。
实际开发中,项目通常具备一个主入口过程,或称为父过程。父过程通过调用多个子过程和函数,完成一系列复杂的操作。其中子过程和函数一般只负责一个操作或动作。
下面看一个简单的例子。
'主入口
Sub Main()
Dim name As String
Dim title As String
name = "Zhang san"
title = "CEO"
WriteInfo name & "," & title
End Sub
'子过程,在工作表A1单元格填写信息
Sub WriteInfo(info As String)
Range("A1") = info
End Sub
以上的例子中,Main 过程是一个主入口(父过程),程序从此处开始执行,先是给 name 和 title 变量赋值,最后调用 WriteInfo 子过程,将两个信息合并后写到工作表上的 A1 单元格。
接下来介绍调用子过程和函数的基本语法。
调用子过程有两种方法,直接调用和使用 Call 关键词调用。两种方法对子过程的参数有不同的要求。
直接调用
直接调用,直接写过程名,即可调用过程。
Sub Main()
MySub
End Sub
Sub MySub()
'代码
End Sub
如果子过程需要输入参数,多个参数只需用逗号(,)分开即可。
Sub Main()
MySub 2019,"年"
End Sub
Sub MySub(val1 As Integer, val2 As String)
'代码
End Sub
使用关键词 Call 调用
使用 Call 关键词调用时,Call 后接过程名。
Sub Main()
Call MySub
End Sub
Sub MySub()
'代码
End Sub
如果子过程需要输入参数,则需要将参数放在括号内。
Sub Main()
Call MySub(2019,"年")
End Sub
Sub MySub(val1 As Integer, val2 As String)
'代码
End Sub
注:程序角度看,调用过程时,不需要使用 Call 关键字,因此不建议此种方法。
提前退出过程
正常情况下,VBA 过程以 Sub 语句开始,以 End Sub 语句结束。但有时根据实际情况,可能需要提前结束并退出过程。VBA 提供 2 种提前退出过程的方法,Exit Sub 和 End 方法。
Exit Sub 语句
在一个过程中,当程序运行到 Exit Sub 语句时,立即结束当前过程,提前退出。
Sub Main()
Call MySub
Msgbox "父过程"
End Sub
Sub MySub()
Exit Sub
Msgbox "子过程"
End Sub
'运行 Main 过程,返回结果:
=> "父过程"
在以上例子中,Main 过程调用 MySub 子过程,遇到 Exit Sub 语句,立即退出子过程,回到父过程 Main ,继续运行余下的语句。
这里需要注意的是,Exit Sub 语句只作用于当前过程,不影响调用它的父过程。
End 语句
在一个过程,当程序运行到 End 语句时,立即结束当前运行的所有 VBA 过程。
Sub Main()
Call MySub
Msgbox "父过程"
End Sub
Sub MySub()
End
Msgbox "子过程"
End Sub
'运行 Main 过程,返回结果:
=> 无返回结果
在以上例子中,Main 过程调用 MySub 子过程,遇到 End 语句时,立即结束当前运行的所有过程,包括父过程 Main。
在实际开发中,应谨慎使用 End 结束语句。End 语句的效果类似于电脑的强制关机命令,立即结束所有程序,不会保存任何值,于 VBA 有以下效果:
程序中对象的各类事件不会被触发;
任何在运行的 VBA 程序都会停止;
对象引用都会失效;
任何打开的窗体都被关闭。
VBA 函数(Function)
VBA 函数基础语法
VBA 函数与 VBA 过程很相似,除了使用的关键词外,主要区别是,函数可以返回值。
无参数函数
无参数 VBA 函数的基本语法如下:
Function [函数名]() As [返回值类型]
语句1
语句2
...
语句n
[函数名] = [返回值]
End Function
可以看到,函数使用 Function 和 End Function 语句作为函数的开始和结束。
函数包含的语句中,相比过程,可以看到多一个 [函数名] = [返回值] 语句,这是函数的返回值语句。函数名后制定该函数返回值的类型,语法与声明变量类似。
看一个实际的例子。
'声明函数,该函数随机返回 true 或 false。函数需指定返回值类型。
Function RandomLogic() As Boolean
RandomLogic = Rnd() > 0.5
End Function
该函数的名称是 RandomLogic,返回值类型时 Boolean 类型,运行调用后,随机返回一个 true 或 false 值。实现方法是,使用 VBA 内置函数 Rnd(随机产生0-1的数字),随机数与0.5对比大小,产生 true 或 false 值,并把值赋值给函数名。
有参数函数
函数与过程一样,也可以接收参数,其语法与过程相同。
Function [函数名]([变量名1] As [数据类型1],...[变量名n] As [数据类型n]) As [返回值类型]
语句1
语句2
...
语句3
[函数名] = [返回值]
End Function
同样,函数接收的参数,在函数主体中使用。
我们看一个实际的例子。
Function Add2Number(num1 As Double, num2 As Double) As Double
Add2Number = num1 + num2
End Function
上述函数接受2个 Double 类型的数字作为参数,两者相加,返回和,其类型也是 Double 类型。
调用函数(Function)
函数与子过程的区别是,函数可以返回值。如果一个函数不返回值,它与子过程并无区别,其中调用方式与子过程相同。
调用有返回值的函数时,一般有两种情形:
一是,使用一个变量存储函数返回的值
二是,函数返回的值参与其他计算
两种情形调用函数方式相同,无参数函数直接书写,有参数函数将参数放在括号内。
Sub Main()
'使用变量存储函数返回的值
Dim result1 As Double
result1 = Add(12, 345)
'函数返回值继续参与计算
Dim result2 As Double
result2 = RandNum + Add(12, 345)
End Sub
'函数:返回一个随机值
Function RandNum()
RandNum = Rnd * 100
End Function
'函数:返回两数的和
Function Add(num1 As Double, num2 As Double) As Double
Add = num1 + num2
End Function
提前退出函数
正常情况下,函数使用 Function 和 End Function 语句作为函数的开始和结束。但有时根据实际情况,可能需要提前结束并退出函数。VBA 提供 2 种提前退出过程的方法,Exit Function 和 End 方法。
Exit Function 语句
在一个函数中,当程序运行到 Exit Function 语句时,立即结束当前函数,提前退出。
这里需要注意的是,Exit Function 语句只作用于当前过程,不影响调用它的父过程或函数。
End 语句
在一个函数,当程序运行到 End 语句时,立即结束当前运行的所有 VBA 过程和函数。
在实际开发中,应谨慎使用 End 结束语句。End 语句的效果类似于电脑的强制关机命令,立即结束所有程序,不会保存任何值,于 VBA 有以下效果:
程序中对象的各类事件不会被触发;
任何在运行的 VBA 程序都会停止;
对象引用都会失效;
任何打开的窗体都被关闭。
VBA 函数与过程的 6 个不同点
第1点:声明语句不同
函数的声明语句是 Function 和 End Function,而过程的声明语句是 Sub 和 End Sub。
下面的代码是函数声明代码:
Function MyFunc()
End Function
下面的代码是子过程声明代码:
Sub SayHello()
End Sub
第2点:函数可以返回值
函数相对子过程最大的不同点是,函数可以返回指定的值。调用函数时,使用一个变量存储函数返回的值,可以在后续的代码中使用。
这里需要指出的是,函数可以不返回值,这种情况其作用与子过程相同。因此建议,不需要返回值时,直接使用子过程代替函数。
第3点:函数需指定返回值类型
VBA 中数据有多种类型,准确使用数据类型可以使程序效率更高。
同样,函数声明时也需要指定其返回值的类型。其语法与变量声明类似,在函数名后指定数据类型。
Function MyFunc() As String '指定返回值类型,此函数将返回文本类型的值
End Function
第4点:函数主体代码中,返回值赋值到函数自己
函数返回一个值,是通过在函数主体代码中,将返回的值赋值到函数自己的方法来实现。
Function MyFunc() As String
'此函数将返回 Hello World 的文本
MyFunc = "Hello World"
End Function
第5点:调用函数时,使用类型与函数返回值类型相同的变量获得返回值
当主程序中调用函数获取其值时,需要使用类型与函数返回值类型相同的变量,否则程序会出错。
Sub MyCode()
Dim text As String '声明与函数返回值相同类型的变量
text = MyFunc '调用函数,获得其返回的值
Range("A1") = text '使用函数返回的值
End Sub
'此函数被上面的过程调用
Function MyFunc() As String
'此函数将返回 Hello World 的文本
MyFunc = "Hello World"
End Function
第6点:函数可在单元格内公式中使用
与 Excel 内置的函数一样,用户自定义编写的函数可在公式中直接使用,其用法与内置函数一样。
自定义函数也一样可以嵌套使用:
VBA 过程和函数:传递参数
VBA 中,调用子过程或函数时,我们可以为它们传递参数。提供的参数可以在子过程或函数内部使用,让程序更动态和灵活。传递参数的前提是,先在子过程或函数定义阶段设置参数,后在调用时按正确的方式提供实际参数值。
本节教程主要介绍传递参数的基础部分,主要内容包括:
带参数的子过程和函数的定义方法。
调用子过程和函数时,参数的书写方式。
可选参数的语法和实际用法。
关于子过程和函数、它们的区别以及如何调用,请看前几节内容。
在子过程和函数中,传递参数的用法基本相同,本节以子过程为例介绍参数的使用,函数中用法参考子过程。
带参数的子过程定义方法
子过程可以接受一个或多个参数,参数可以是常量、变量、表达式,并且每个参数指定其名称和数据类型。
看实际的例子,以下代码定义了带两个参数的一个过程,过程名是 CustomLog ,参数分别是 num 和 base。此过程的用途是计算任意底数的对数,num 是计算对数的值,base 是底数。
'声明一个带参数的子过程
Sub CustomLog(num As Double, base As Integer)
Debug.Print Log(num) / Log(base)
End Sub
子过程按照这种方法定义后,调用时,VBA 会提示需要提供什么参数以及参数类型。
调用带参数的子过程
调用带参数的过程,只需将参数按定义顺序书写即可,多个参数使用逗号分开。
以上述过程为例,在一个主过程调用 CustomLog 子过程。
'主入口
Sub Main()
CustomLog 100, 10
End Sub
除了按顺序书写参数外,也可以按任意顺序书写参数,但是这时需要给出参数名。带参数名的传递参数语法如下:
[参数名]:=[实际参数值]
参数名后写冒号等号(:=),再写需传递的参数值。看实际的例子,以下三种方式是等效的。
'主入口
Sub Main()
CustomLog 100, 10 '方式一
CustomLog num:=100, base:=10 '方式二
CustomLog base:=10, num:=100 '方式三
End Sub
可选参数的用法
实际开发中,有时子过程的参数可能不是必须的,我们希望根据参数有无情况,执行不同的操作。针对这种情况,VBA 提供了可选参数机制。
可选参数语法
可选参数在定义子过程时需要指定,方法是在参数名前添加 Optional 关键词。
Optional [参数名] As [数据类型]
还是以 CustomLog 子过程为例,我们把底数 base 设为可选参数。
'声明一个带可选参数的子过程
Sub CustomLog(num As Double, Optional base As Integer)
'子过程代码
End Sub
调用时,VBA 会提示可选参数,参数放置在中括号中。
设置可选参数的默认值
可选参数定以后,如果在子过程中使用,需要判断参数有无提供。否则未提供而直接使用时,程序会出错。
针对这种情况,VBA 提供了默认值机制,即可选参数未提供时,使用预算设置好的默认值。
可选参数默认值,在定义过程时就设置,语法如下:
Optional [参数名] As [数据类型] = [默认值]
还是以 CustomLog 子过程为例,我们把底数 base 设为可选参数,并且默认值设为 10。
'声明一个带可选参数的子过程
Sub CustomLog(num As Double, Optional base As Integer = 10)
Debug.Print Log(num) / Log(base)
End Sub
调用时,如果提供了 base 底数,则以提供的底数计算;如果未提供 base 底数,则以默认值 10 计算。
'主入口
Sub Main()
CustomLog 100, 100 '返回 1
CustomLog 100 '返回 2
End Sub
可选参数的位置
当子过程有多个参数时,其中的可选参数需写在参数列表的末尾,否则 VBA 提示错误。
可选参数错误顺序:
可选参数的正确顺序:
VBA 中 ByVal 和 ByRef 的基础用法和区别
BA 中定义过程或函数时,如果需要传递变量,需指定参数的传递类型,包括以下 2 类:
ByVal:传递参数的值
ByRef:传递参数的引用
ByVal 和 ByRef 基础
在定义过程或函数时,如果需要传递变量,则每个参数需要指定传递类型。传递类型有 2 种,分别是 ByVal 和 ByRef 。
'ByVal 传递类型
Sub TestSub1(ByVal msg As String)
End Sub
'ByRef 传递类型
Sub TestSub2(ByRef msg As String)
End Sub
针对基础数据类型,例如数字、文本等,两种传递类型的说明和区别如下:
ByVal:传递变量时,复制一份该变量,传入过程或函数。在过程和函数内部对该变量进行修改,只对该副本有效,对上一级过程(父过程)的变量没有影响。
ByRef:传递变量时,将该变量的引用地址传入过程或函数。传入引用地址意味着,在过程或函数内部对其修改时,也会影响上一级过程(父过程)中的变量的值。
ByVal 实例
通过以下代码测试 ByVal 类型:
Sub Test()
Dim msg As String
msg = "main"
TestSub1 msg
Msgbox msg
End Sub
'ByVal 传递类型
Sub TestSub1(ByVal msg As String)
msg = "val"
End Sub
首先定义一个 msg 变量,赋值 main,然后调用 TestSub1 过程,传入 msg 变量,在过程内部对 msg 重新赋值 val。最后返回上一个过程,显示 msg 变量。结果如下,msg 变量的值没有改变。
ByRef 实例
通过以下代码测试 ByRef 类型:
Sub Test()
Dim msg As String
msg = "main"
TestSub2 msg
MsgBox msg
End Sub
'ByRef 传递类型
Sub TestSub2(ByRef msg As String)
msg = "ref"
End Sub
首先定义一个 msg 变量,赋值 main,然后调用 TestSub2 过程,传入 msg 变量,在过程内部对 msg 重新赋值 ref。最后返回上一个过程,显示 msg 变量。结果如下,msg 变量的值已改变。
省略传递类型
默认情况下,当省略传递类型时,默认值是 ByRef,因此以下两种写法是等效的。
'指定 ByVal 传递类型
Sub TestSub1(ByRef msg As String)
End Sub
'省略传递类型
Sub TestSub1(msg As String)
End Sub
使用 ByVal 和 ByRef 传递对象
在上述介绍中说道,以上机制适用于传递基础类型变量,例如数字、文本、逻辑值等。
使用 ByVal 和 ByRef 传递对象时,情况有些不同。具体用法和不同点将在介绍对象时详细说明。
使用 ByVal 和 ByRef 传递数组
过程或函数传递数组时,只能以引用形式传递,即以 ByRef 形式。如果尝试用 ByVal 传递数组,VBA 会提示错误。详细的用法将在介绍数组时详细说明。
小结
ByVal 和 ByRef 表示参数传递的类型。针对基础数据类型的变量,ByVal 会创建变量的一个副本,传递给过程或函数,从此之后与父过程的变量没有关系。而 ByRef 方式传递变量的引用,该引用始终会与父过程的变量相连。
因此建议,尽量使用 ByVal 传递类型,防止在子过程或函数中,不小心更改父过程里的变量,导致一些不容易发现的问题。
VBA 变量作用域
VBA 中,变量的作用域决定变量在哪里能被获取和使用。根据变量的声明位置和声明方式,变量的作用域有以下 4 种:
过程作用域
模块作用域
工程作用域
下面将逐一介绍每一种作用域对应的变量的声明方法以及使用方法。
1.过程作用域
在过程或函数内部声明的变量,只有在当前过程或函数内被使用。例如:
Sub Test()
Dim name As String
Dim age As Integer
name = "张三"
age = 35
End Sub
以上代码中,变量 name 和 age 在 Test 过程声明,因此它们只能在该过程中内使用,包括赋值和读取。如果尝试在外部和其他过程中直接使用它们,VBA 会提示变量未定义错误。
2.模块作用域
一个模块中,在任何一个过程和函数外面,使用关键词 Private 或 Dim 声明的变量,称之为模块变量,其作用域是当前模块。例如,
Dim guest As String
Sub Test()
Dim message As String
guest = "张三"
message = "你好"
MsgBox message & "! " & guest
End Sub
以上代码中,变量 guest 是在过程 Test 外面,使用 Dim 关键词声明的,称之为模块变量。模块变量的作用域是当前模块,在模块里面任何过程和函数内均可以使用。
如前文所述,使用关键词 Private 或 Dim 声明的变量,都是模块变量,因此以下两种声明方式是等效的。
Dim guest As String
Private guest As String
3.工程作用域
Excel VBA 中,一个Excel 工作簿是一个 VBA 工程。与之对应,工程作用域表示变量在当前工程中的模块、Excel 对象、用户窗体、类模块中均可以被使用。
工程级别变量,在所在模块顶部声明 Option Private Module 修饰语句前提下,在过程或函数外面,使用关键词 Public 声明的变量,其作用域是当前工程。例如,
Option Private Module
Public guest As String
Sub Test()
Dim message As String
guest = "张三"
message = "你好"
MsgBox message & "! " & guest
End Sub
以上例子中,变量 guest 是使用 Public 关键词声明,是工程级别变量。它在当前工程中其他的模块中也能被使用。
作用域冲突
当相同名称的变量,多次以不同的作用域声明时,出现作用域冲突。这种情况,VBA 会自动以就近原则使用变量,即优先使用最近定义的变量。例如,
Dim name As String
Sub Test()
Dim name As String
name = "李四"
End Sub
以上例子中,两次声明 name 变量,分别是模块变量和过程变量。根据就近原则,在过程内部使用时,将使用过程变量。
VBA 过程或函数作用域
VBA 中的过程和函数,与变量类似,也具有不同的作用域。根据声明位置和方式,有 3 种作用域:
模块作用域
工程作用域
全局作用域
1.模块作用域
在模块中,使用 Private 关键词声明的过程或函数,具备模块作用域,只能在当前模块中使用。
Private Sub Test()
End Sub
2.工程作用域
在模块中,顶部声明 Option Private Module 修饰语句,并且直接声明或使用 Public 关键词声明的过程或函数,具备工程作用域,在当前工程的所有模块中使用。
Option Private Module
Sub Test1()
End Sub
Public Sub Test2()
End Sub
以上例子中,Test1 过程和 Test2 过程均具备工程作用域。由于直接声明和使用关键词 Public 是等效的,因此可以省略 Public 关键词。
3.全局作用域
在模块中,直接声明或使用 Public 关键词声明的过程或函数,具备全局作用域。例如,
Sub Test1()
End Sub
Public Sub Test2()
End Sub
以上例子中,Test1 过程和 Test2 过程均具备全局作用域,可以在打开的任何一个工作簿中使用。
此外,它们还能直接在工作簿宏列表中执行。
文章转载自「懒人Excel - www.lanrenexcel.com」