- 进入开发工具窗口

2.选择插入模块,然后插入过程,选择子程序


在Excel中,数据只有文本,数值,日期值,逻辑值和错误值五种类型。但是在VBA中,数据类型跟Excel不完全相同。根据数据的特点,VBA将数据分为布尔型(boolean),字节型(byte),整数型(integer),单精度浮点型(single),双精度浮点型(double),货币型(currency),小数型(decimal),字符串型(string),日期型(date),对象型等等
声明变量,其实就是指定该变量的名称及其可存储的数据类型,要在VBA中声明一个变量,有以下几种方法:
- Dim 变量名 as 数据类型
- Private 变量名 as 数据类型,用private声明变量,该变量将会变成私有变量
- Public 变量名 as 数据类型,用public变量定义的变量是公有变量
- static 变量名 as 数据类型,如果使用static声明变量,这个变量将会变成静态变量,当程序结束后,静态变量会保持其原值不变。
- 给数据类型的变量赋值,应该要使用这个语句:let 变量名称 = 要存储的数据
- 给对象类型的变量赋值,应该使用下面的语句:“set 变量名称 = 要存储的对象名称”

- 数据型变量参与运算

2. 对象型变量参与运算

- 如果要声明多个变量可以将代码写成下面形式:

2. 可以使用变量类型声明符定义变量类型

- 声明变量可以不指定变量类型:在VBA中声明变量是,如果不确定会将类型的数据存储在变量中,可以在声明变量时,只定义变量的名字,而不是变量的类型。如果声明变量时,只指定变量的名称而不指定变量的数据类型,VBA默认将该变量定义为Variant类型,如果一个变量被声明为variant类型,俺么它能够存储任何数据类型
- 强制声明所有变量:如果担心自己忘记在程序中忘记声明变量,可以在模块开头,输入“Option Explicit”
按作用域划分,VBA中的变量可以划分为本地变量,模块变量和公共变量。
- 数组就是同种类型的多个变量的集合
- 数组中的元素可以通过索引值取出
- 声明数组时应该声明数组的大小
“public dim 数组名称 (a to b)as 数据类型” - 给数组赋值就是给数组的每个元素分别赋值
这里是声明一个叫arr数组,其形状为a行b列
当声明数组时,不知道要在这个数组中填入多少个数据时,可以使用动态数组。将数组声明为动态数组时,不能直接使用变量,需要之后使用redim 重新制定数组大小

- 使用array函数声明数组

2. 使用是split函数声明数组

- 通过单元格区域直接创建数组

利用UBound求数组的最大索引号
利用LBound函数求最小索引号
求多维数组的最大和最小索引号

用join函数将一维数组合并成字符串
将数组内容写入工作表中
其中transpose是对数组进行列转换。数组内容如果不够填充单元格长度,超出的数据会以NA值填充。若需要填充的单元格数目不够数组长度,那么会按照顺序依次填充。
数组的存取
当将Excel表中的数据传递给数组时,默认建立的是一个二维数组,因此在取数组的值时,需要传递两个数值进去,如果只传入一个数组,会出现下标越界的警告。数组的第一个数指定行,第二个数指定列
常量常常用来存储一些固定不变的数据,如利率,税率和圆周率等。**声明常量时,英同时定义常量的名称,可存储的数据类型以及存储在其中的数据。语句为:
同定义变量一样,在过程内部使用const语句定义的常量称为本地常量,只可以在声明常量的过程中使用;
如果在模块的第一个过程之前使用const语句声明常量,该常量被称为模块级常量,该模块中的所有过程都可以使用它;
如果想让声明的常量在所有模块中都可以使用它,那么应该在模块的第一个过程之前使用public语句将它声明为公共常量。
对象就是东西,使用VBA代码操作和控制的东西,属于名词。在VBA中,Excel的工作簿,工作表,单元格等都是对象,图表,透视表,图片等也都是对象,甚至于单元格的边框线,插入的批注都是对象…
集合也是对象,它是对多个相同类型对象的统称。
每个对象都有属性,对象的属性可以理解为这个对象包含的内容或者具有的特征。对象和属性是相对而言的。单元格相对于字体来说的对象,但是单元格相对于工作表而言是属性
方法是在对象上执行的某个动作或者操作,每个对象都有其对应的一个或者多个方法。方法和属性的区别是属性返回对象包含的内容或者具有的特点,如子对象、颜色、大小等;方法是对对象的一种操作,如选中,激活等
算数运算符
比较运算符
通配符
逻辑运算符
函数虽然很多,但是我们不需要很精确的记住它们。**如果记得某个函数大致拼写,在编写代码时只要在【代码窗口】中输入“VBA.”,就可以在系统显示的函数列表中选择需要使用的函数。
在VBA中,if语句的规则如下:

select case语句
尽管使用if语句可以解决“多选一”的问题,但当判断的选择条件过多时,使用多个elseif语句或多个if语句,就像一句话里用了太多的如果,会为理解代码逻辑带来困难。通常,当需要在三种或以上的策略中做出选择时,我们会选择使用select case 语句来解决问题
for 循环
在VBA中定义for循环的语法规则如下:
for循环都要以next结尾

for each…next语句循环处理集合或数组中的成员
当需要循环处理一个数组的每个元素或者集合中的每个成员时,使用for each……next语句
do while循环
do while语句可以分为两种,按照设置循环条件的位置区分,可以分为开头判断式和截尾判断式。其语句结构如下:
- 开头判断式
- 截尾判断式
每个do语句都必须以loop结尾,当循环进行到loop处时,会重新回到do语句判断条件是否成立
使用Goto语句,让程序转到另一条语句去执行
要让goto语句清楚的知道要转向的目标语句,可在目标语句之前加上一个带冒号的文本字符创,或者不带带冒号的数字标签,然后在goto的后面写上标签名

with语句,简写代码
当需要对相同的对象进行多次操作时,往往会编写一些重复的代码。如果不想重复多次的录入相同的语句,可以用with语句简化

private或public用来声明过程的作用域,同时只能使用一个,可以省略,如果省略,默认使用public。如果选用static,过程执行结束后,会继续保存过程中变量的值
- 直接使用过程名调用过程,过程名与参数之间用英文逗号隔开
- 使用call关键字调用过程,参数写在过程小括号中,不同参数之间用逗号隔开
- 使用application对象的run方法调用过程
在VBA中,过程的参数传递主要有两种形式:按引用传递和按值传递。默认情况下,过程是按照引用的方式传递参数的。如果程序通过引用的方式传递参数,只会传递保存数据的内存地址,在过程中对参数的任何修改都会影响原始的数据。
无论function过程包含多少代码,要执行多少计算,都应该将最后的计算结果保存在过程名称中,这相当于其他语言中的函数return内容
- 在Excel中使用:
如果定义的函数没有被定义为私有过程,那么我们可以通过【插入函数】在Excel中使用我们自定义的函数。

- 在VBA过程中使用

有时,当工作表重新计算后,自定义函数并不会重新计算。如果想让工作表重新计算后,自定义的函数也能随之重新计算,就应该讲自定义函数定义为易失性函数。要将一个自定义函数定义为易失性函数,只需要在function过程开始时添加下面一行代码:
example
使用ScreenUpdating属性设置更新屏幕
application对象的ScreenUpdating属性是控制屏幕更新的开关。如果设置其为false,那么屏幕将不会更新,我们将不会看到每一步的执行结果
设置DisplayAlerts属性禁止显示警告对话框
当我们在Excel中执行某些操作时,Excel会显示一个警告框,让我们确定是否执行这些操作。由于很多原因,我们都希望Excel在程序执行中不显示类似的警告对话框,这样可以通过设置application对象的displayalerts属性为false来实现
借助worksheetfunction属性使用工作表函数
VBA中有许多的内置函数,合理使用函数可有效减少工作中的许多难题,减少编写代码的工作量。但是VBA中没有Excel的内置函数,使用worksheetfunction可以调用Excel中的内置函数。
如果VBA中已经有了相同功能的函数,就不能再通过worksheetfunction属性引用工作表中的函数。并且并不是所有的工作表函数都可以通过worksheetfunction属性来调用
设置属性,更改Excel的工作界面
设置application对象的属性来修改Excel的界面
application的子对象
application对象的常用属性
引用workbook对象
- 通过文件索引引用
- 通过文件名引用
访问workbook对象属性
创建工作簿——add
- 创建空白工作簿:如果直接调用workbook对象的add方法,而不设置任何参数,excel将创建一个只含普通工作表的新工作簿
- 指定用来创建工作簿的模板: 如果想将某个工作簿文件作为新建工作簿的模板,可以使用add方法的template参数指定该文件的名称及其所在的所在目录
- 指定新建工作簿包含的工作簿类型
用add方法的参数指定新建的工作簿包含的工作表类型
用open方法打开工作簿
activate激活工作簿
保存工作簿
- save方法保存已存在的文件
- saveas方法将工作簿另存为新文件
- 另存为新文件后不关闭原文件
close——关闭工作簿
add方法新建工作表
- 在活动工作表前插入一张工作表
- 用before|after参数指定要插入工作表的位置
- 用count 参数指定要插入的工作表数量
设置name属性,更改工作表的标签名称
用delete方法删除工作表
激活工作表的两种方法
用copy方法复制工作表
- 将工作表复制到指定位置
- 将工作表复制到新工作簿中
使用move移动工作表
- 将工作表移动到指定位置
- 将工作表移动到新工作簿中
设置visible属性,隐藏或者显示工作表
访问count属性,获得工作簿中工作表的数目
用range属性引用单元格
- 引用单个固定的单元格区域:这种方法实际上就是通过单元格地址来引用单元格
- 引用多个不连续的单元格:将range属性的参数设置为一个用逗号分成多个单元格地址组成的字符串
- 引用多个区域的公共区域:将range属性设置成为一个用空格分割的多个单元格地址组成的字符串
- 引用两个区域围成的矩形区域
用cell属性引用单元格
- 引用工作表中指定行列交叉的单元格
- 引用单元格区域中的某个单元格
- 将cells属性的返回结果设置为range属性的参数
- 使用索引号引用单元格
引用整行单元格
在VBA中,rows表示工作表或某个区域中所有行组成的集合,要引用工作表汇总指定的行,可以使用行号或者索引号两种方式
引用整列单元格
在VBA中,columns表示工作表或某个区域中所有行组成的集合,要引用工作表汇总指定的行,可以使用行号或者索引号两种方式
使用union方法合并多个单元格区域
application对象的union方法返回参数指定的多个单元格区域的合并区域,使用该方法可以将多个range对象组合在一起,进行批量操作。
range对象的offset属性
使用offset属性,可以获得相对于指定单元格区域一定偏移量位置上的单元格区域。offset有两个参数,分别用来设置该属性的父对象在上下或者左右方向上偏移的行列数
range对象的resize属性
使用range对象的resize属性可以将指定的单元格区域有目的地扩大或者缩小,得到一个新的单元格区域。
worksheet对象的usedrange属性
worksheet对象的usedrange属性返回工作表中已经使用的单元格围城的矩形区域.usedrange属性返回的总是一个矩形区域,无论这些区域是否存在空行,空列或者空单元格
range对象的currentregion属性
range对象的currentregion属性返回包含指定单元格在内的一个连续的矩形区域,空行及下面的区域以及空列及右面的区域不包含在currentregion区域内
range对象的end属性
range对象的end属性返回包含指定单元格的区域最尾端的单元格,返回结果等同于在单元格中按【enter+方向键】得到的单元格
end参数及说明
value属性——单元格中的内容
count属性,获得区域中包含的单元格个数
通过address属性获取单元格地址
用activate和select方法选中单元格
copy方法复制单元格区域
无论复制多少单元格,destination参数只需要指定左上角单元格坐标就好
cut方法剪切单元格区域
无论剪切多少单元格,destination参数只需要指定左上角单元格坐标就好
用delete方法删除指定的单元格
调用range对象的delete方法可以删除指定的单元格,但与手动删除单元格不同,通过VBA代码删除单元格,excel不会显示【删除】对话框。想让excel在删除指定的单元格后,按自己的意愿处理其他单元格,我们需要编写VBA代码将自己的意图告诉excel。如想删除B3所在的整行单元格,应将代码写为:
根据需求创建工作簿
利用VBA创建一个符合自己需求的工作簿,并将其保存到指定的目录中
判断某个工作簿是否已经打开
判断文件夹中是否存在指定名称的工作簿文件
向未打开的工作簿中输入数据
隐藏活动工作表外的所有工作表
批量新建指定名称的工作表
批量对数据进行分离,并保存到不同的工作表中
将多张工作表中的数据合并到一张工作表中
将工作簿中的每张工作表都保存为单独的工作簿文件
将多个工作簿中的数据合并到同一张工作表中
为同一工作簿中的工作表建一个带链接的目录
其中参数anchor指定建立超链接的位置,address指定超链接的地址,subaddress指定超链接的子地址,TexttoDisplay指定用于显示超链接的文字
- 打开thisworkbook的代码窗口
- 选择workbook对象,在声明中选择open
- 编写子程序

当某个事件放生后自动运行的过程,称为事件过程,事件过程也是sub过程 。与sub过程不同的是,时间过程的作用域,过程名称及参数都不需要我们设置,也不能随意设置。时间过程的过程名称总是由对象名称及时间名称组成的,对象在前,事件在后,二者之间用下划线连接。
工作表事件就是发生在worksheet对象中的事件,一个工作簿中可能包含多个worksheet对象,而worksheet事件过程必须写在相应的worksheet中,只有过程所在的worksheet对象中的操作才能触发相应的事件。
worksheet对象的change事件
worksheet对象的change事件告诉VBA:当过程所在工作表中的单元格被更改时自动运行程序。
编写事件过程,通常我们都采用这种方式:依次在【代码窗口】的【对象】列表框和【事件】列表框中选择相应的对象及事件名称,让VBA自动替我们设置事件过程的作用域、过程名称以及参数信息
- 更改单元格时自动执行
- 更改部分单元格时自动执行
禁用事件,让事件过程不再自动执行
禁用事件就是执行操作后不让事件发生。在VBA中,可以设置application对象的EnableEvents属性为false来禁用事件
selectionchange事件:当选中的单元格改变时发生
worksheet对象的selectionchange时间告诉VBA:当更改工作表中选中的单元格区域时自动执行该事件的事件过程。
高亮选择区域的相同值
用批注记录单元格中数据的修改情况
worksheet对象一共有17个时间,可以在【代码窗口】的【事件】列表框或VBA帮助中查看这些事件
常用的worksheet事件
工作簿事件是发生在workbook对象中的事件,一个workbook对象代表一个工作簿,workbook对象的事件过程必须写在ThisWorkbook模块中,可以在【工程资源管理器】中找到这个模块
open事件:当打开工作簿时发生
open事件是最常用的workbook事件之一,同国外吗会使用该事件对excel进行初始化设置,如设置想打开工作簿看到的excel窗口或工作界面,显示我们自定义的用户窗体等
beforeclose事件: 在关闭工作簿之前发生
sheetchange事件:更改任意工作表中的单元格时发生
常用的workbook事件
application对象的onkey方法
OnKey方法告诉excel,当按下键盘上指定的键或者组合键时,自动执行指定的程序
在onkey中可以设置的按键及其对应代码
Application对象的OnTime方法
Ontime方法告诉VBA,在指定的时间自动执行指定的过程
Ontime的DateSerial参数可以设置指定的年月日;Scheduled的值如果为TRUE,会新设置一个Ontime过程,如果为False,就会清除之前设置的过程,默认值为TRUE
让文件自动保存
excel中有两种类型的控件:表单控件和ActiveX控件。可以在excel的【功能区】中找到它们
- 表单控件
- ActiveX控件:excel中有11中可用的ActiveX控件,但是工作表总使用的ActiveX控件不止这些,可以单击其中的【其他控件】按钮,在弹出的对话框中选择其他控件
在工作表中使用控件
- 添加表单控件

2. 绘制表单控件

3. 设置相应区域

在工作表中使用ActiveX控件
- 添加ActiveX控件

2. 设置属性

- 编写控件代码
- 显示内容

用InputBox函数创建一个可输入数据的对话框
Input函数共有5个参数:
- prompt参数用于设置在对话框中显示的提示消息
- title用于设置对话框的标题
- default用于设置默认的输入值
- xpos用于设置对话框与左端与屏幕左端的距离
- ypos用于设置对话框的顶端与屏幕顶端的距离

用input方法创建交互对话框
用application对象的inputbox方法也可以创建于程序互动的对话框,但要注意与Inputbox函数相比,Input方法的参数有些许不同
type参数的可设置项及说明
使用msgbox函数创建输出对话框

设置在对话框中显示的按钮样式
不同图标的参数设置
设置对话框中的默认按钮
常数|值|说明
vbDefaultButton1 | 0 | 第一个按钮为默认值
vbDefaultButton2 | 256 | 第二个按钮为默认值
vbDefaultButton3 | 512 | 第三个按钮为默认值
vbDefaultButton4 | 768 | 第四个按钮为默认值
指定对话框的类型
buttons参数的其他设置
MsgBox函数的返回值
使用FindFile方法显示【打开】对话框
使用application对象的FindFile方法可以显示【打开】对话框,在对话框中选择并打开某个文件
用GetOpenFileName方法显示【打开】对话框
与findfile方法不同,使用GetOpenFileName方法是获得在对话框中选中的文件的文件名称(包含路径),而findfile是打开在对话框中选中的文件
- 选择任意文件
- 只在对话框中显示某种类型的文件
- 让对话框同时显示多种扩展名文件
- 让对话框能选择显示多种类型的文件
- 通过FilterIndex参数设置默认显示的文件类型
如果在【文件类型】下拉列表中设置了多种可选择的文件类型,就可以通过GetOpenFileName方法的FiterIndex参数,设置对话框中默认显示的文件类型
- 设置允许同时选择多个文件
默认情况下,在通过GetOpenFileName方法显示的【打开】对话框中,只能同时选中一个文件,如果希望同时选中多个文件,可以将MultiSelect参数设置为TRUE
- 修改对话框标题
用GetSaveAsFilename方法显示【另存为】对话框
要想获得选中的文件名称,还可以调用application对象的GetSaveAsFilename方法打开【另存为】对话框,在对话框文中选择文件,获得该文件包含路径信息的文件名称
使用application对象的FileDialog属性获取目录名称
如果想要获得的不是文件名,而是指定目录的路径及名称,可以使用application对象的FileDialog属性。
msoFileDialogType参数可以设置的常量
很多时候,我们都希望自己能够设计一个交互界面,定义其中的控件及控件的功能,这就需要用到VBA中的另一类常用对象——Userform对象。一个用户窗体就是一个Userform对象,也就是大家常说的窗体对象。当在工程中添加一个窗体后,就可以在窗体上自由的添加ActiveX控件,只要通过编写VBA代码为这些控件指定功能,就能利用这些控件与excel互动
- 在工程中添加一个用户窗体

- 设置属性,改变窗体的外观

- 在窗体中添加和设置控件的功能

显示窗体
- 手动显示窗体
在VBE窗口中选中窗体,依次执行【运行】——>【运行子过程/窗体】命令,即可显示选中的窗体
- 在程序中用代码显示窗体

将窗体显示为无模式窗体
- 模式窗体不能操作窗体之外的对象
要将窗体显示为模式窗体,可以使用代码
或者省略show方法的参数,或者将参数设置为vModal,VBA都会讲窗口见识为模式窗体
2. 无模式窗体允许进行窗体外的其他操作
要将窗体显示为无模式窗体,必须通过show方法制定参数
如果将窗体显示为无模式窗体,当窗体显示后,系统会继续执行程序余下的代码,也允许我们操作窗体之外的其他对象
关闭或隐藏已显示的窗体
- 用unload命令关闭窗体
- 使用Hide方法隐藏窗体
借助Initialize事件初始化窗体
Initialize事件发生在显示窗体之前,当我们在程序中使用load语句加载窗体,或者使用show显示窗体时,都会引发该时间
借助QueryClose事件让窗体自带的【关闭】按钮失效
queryclose事件过程是一个带两个参数的sub过程,其中的cancel参数确定是否响应我们关闭窗体的操作。当值为TRUE时,程序将不响应我们关闭窗体的操作。如果cancel的值为false,程序将关闭窗体。其中CloseMode参数是我们关闭窗体的方式,不同的关闭方式返回的值也不相同
CloseMode参数的返回值说明
为【确定】按钮添加事件过程
给控件设置快捷键
给按钮设置了快捷键后,显示窗体时,当按下对应的快捷键就等于在窗体中用鼠标单击了该按钮。
更改控件的Tab键顺序
只有对象被激活时,才能几首键盘输入。控件的Tab键顺序决定用户按下【Tab】或【Shift+Tab】组合键后控件激活的顺序。在设计窗体时,系统会按照添加控件的先后顺序确定控件的Tab顺序。但是这个顺序是可以更改的。在VBE中选中窗体,依次执行【视图】——>【Tab键顺序】命令。调出Tab键顺序对话框,即可在其中调整控件的Tab键顺序

- 设计窗体显示

2. 添加代码,为控件指定功能
On Error GoTo 标签实际就是在“on error”的后面加了一个GoTo语句,其中的“标签”就是替goto语句设置的标签,是一个数字或者带冒号的文本。标签告诉VBA,当程序运行过程中晕倒运行时错误时,跳转到标签所在行的代码继续执行程序,实际上就是让程序跳过出错的代码,从另一个地方重新开始执行程序。
Resume Next告诉VBA,如果程序发生错误,则忽略存在错误的代码,接着执行错误行之后的代码。如果程序一开始加入On Error Resume Next语句,运行程序时,及时程序中存在运行时错误,VBA也不会中断程序,而是忽略所有存在错误的语句,继续执行出错语句后的代码
使用On Error GoTo 0语句后,将关闭对程序中运行时错误的捕捉,如果程序在On Error GoTo 0语句后出现运行错误,将不会被捕捉到