VBA笔记入门篇

VBA笔记入门篇

VBA全名:  Visual  Basic  Application

准备·工作

打开VBA

打开左上角的:文件->选项 弹出如下画面,选择“自定义功能区”,勾选上“开发工具”,点击确定。Excel的头上就会多出一个选项卡:开发工具。

 

 

另一种打开方式:

在excel头部的任意一个选项卡里单击右键,在弹出的菜单里选第三项“自定义功能区域”。也可以弹出如上画面。

启用宏

因为很多病毒是靠VBA的宏传播,所以excel默认禁止执行宏,所以要执行VBA先要允许宏启动。在“开发工具”选项卡里点击“宏安全性”,选“宏设置”,选中“启用所有宏”。点击确定按钮,然后重启excel(关闭excle文件再重新打开)

 

VBA编辑器

点击“开发工具”中的“Visual Basic”,可以打开VBA编辑器。

VBA编辑器简称BE,即Visual Basic Editor

 

 

在资源管理器中并没有“模块”这样的目录结构,需要添加进去。在资源管理器中,右键单击,弹出菜单中选择“插入”,然后选择“模块”

 

双击资源管理器中的“模块1”,就可以在右边开发代码。

 

开发第一个小程序

点击一个按钮,计算execl中的公式

添加按钮

1、点击“插入”,弹出表单控件,选中按钮控件

 

2、选中按钮控件后,在excel需要添加按钮的地方,拖动鼠标左键画出按钮,弹出设置按钮调用宏信息的top画面。给宏起一个方法名,然后点击“新建”按钮,创建代码。然后进入VBA编辑器。看到如下代码。而且在资源管理器中自动给我们创建了一个“模块2”对应此代码。

宏:在VBA中编写的一段小程序(Macro)

 

 

Cells(行,列单元格行列取值

编辑代码

 

编辑完代码后保存文件,会弹出提示,我们必须把文件另存为xlsm格式文件,否者编写的代码无法保存。

回到excel画面,点击按钮就会计算出A1+A2的结果,结果放在C1单元格中。

 

编辑按钮文字 -> 右键单击按钮选第四项“编辑文字”(也可以拖动按钮位置)

调整编辑器字体

首先进入excle中的VBA编程界面,在顶部菜单栏中找到工具的按钮,点击工具”,找到选项按钮,然后进入选项的编辑界面,点击编辑器格式”,在右边可以选择字体的大小。

先写宏后关联按钮

1、先在模块2中创建一个做减法的宏代码

 

2、然后新建一个按钮,在弹出的top画面中,把按钮关联到这个宏上。

 

这样点击这个新建的按钮,C1就会等于A1-B1

VBA语法

变量

区别:

VBA的变量规则与java基本一致,最大的不同有以下两点:

1、VBA变量大小写不敏感 xy = XY = xY

2、当VBA程序中遇到一个新的变量名时,VBA会自动创建该变量,无需事先声明。

 

上面的代码x取一个固定单元格的值,程序根据单元格的值,计算对应行的数据。

注意:因为vba定义变量不像Java有变量初始化,Java程序一旦调用没有定义过的变量编译会出错。vba没有定义变量初始化,所以调用一个不存在的变量不会报错,他会自动创建这个变量,只是这个变量没有值。(所以把一个变量名修改后,后面调用这个变量的地方一旦漏改,程序不会报错,但是结果会出错)

为了应付没有定义变量调用也不会报错的情况,可以在程序里事先声明程序里只使用以下变量。

强制声明变量:

必须写在该模块文件的第一行写上Option Explicit,然后在方法体中用Dim声明,并用逗号分隔。一旦声明dim的方法体里使用了没有用dim声明的变量,编译就会报错。

 

常量

不可以被修改的变量,一旦定义成了常量,修改这个值会报编译错误。代码写法如下:

Const p = 3.14

FOR循环

 

上述代码for循环是:i从11循环到20,步长是1(循环一次加1)

注意:For循环结束处的 Next i,i可以省略不写。(for循环套for循环的时候建议写,否者不知道那个结束end是属于哪个for循环的)

如果步长是每次增加1,step 1也可以省略不写。其他情况例如递减需要写成step -1。

(使用tab键让代码缩进关系统一)

While循环

第一种:

While  Cells(1,2) <> “”

       …

Wend

第二种:(常用)

Do While Cells(1,2) <> “”

       …

Loop

 

例子代码:遍历每一个sheet页,计算每一个sheet页面的指定表格数据

 

IF ELSE

1、基本用法

下面的宏关联按钮后,点击按钮会根据A1和A2单元格的值在A3中写入合格或不合格,以下就是if else的用例:

Sub ifElseTest()

    Dim score1, score2

    score1 = Cells(1, 1)

    score2 = Cells(1, 2)

    '当A1和A2单元格都大于60的时候,A3单元格显示合格

    If score1 > 60 And score2 > 60 Then

        Cells(1, 3) = "合格"

    Else

        Cells(1, 3) = "不合格"

    End If

End Sub

2、如果判断语句写在同一行,那么可以不写End IF,例:

If score1 > 60 Then  Cells(1, 3) = "合格"

3、ElseIf:(ElseIf 是一个关键字)

 

 

关系运算符

大于:>    小于:<    大于等于: >=   小于等于:<=    不等于: <>   等于:=

逻辑运算符

与:And   或:or   非:not

字符串

字符串连接用&符号,记得字符串用&连接时,字符串与&符号之间一定要有空格,否者会引发歧义。

    str1 = "a"

    str2 = "b"

    Cells(2, 1) = Cells(2, 1) & str1 & str2

程序调试debug

1、设置断点:直接在vba编辑器中找到要调试的代码,点击左侧竖栏,生成断点。运行程序代码会到此处停下。

 

2、单步执行 F8  (VBA编辑器点开“调试”,里面能看到所有调试方法和快捷键)

 

3、添加监视:

 

 

 

4、报错自动定位:

如果运行时代码出错,VBA会弹出提示出错,点击弹出框的“调试”,会自动定位到出错行

 

 

宏操作excel

设置单元格字体颜色

Sub setCellsStyle()

    '把A1到C2之间(矩形的左上角与右下角范围)所有单元格字体变为红色

    Range("A1:C2").Font.Color = -16776961

End Sub

 

根据上例发现,Excel中每一个元素的操作都有对应的对象,例如Cells就是操作单元格的,Range就是范围操作单元格的,对应的excel中各种图形等都有固定的调用方法,但是我们不可能记住每一种图形的调用对象,所以我们可以利用excel录制宏的方法操作格个图形对象,然后看录制宏的代码,就知道了每种对象如何调用。

录制宏-参照宏代码

Excel提供了一种记录我们操作excel动作的“录制宏”功能,只要我们记录住操作excel的动作,再执行录制的宏,excel就会重复我们录制的动作。我们可以查看excel生成的代码,了解这些宏如何操作控件,从而根据这些代码来完成我们的代码。

例:我们想知道删除行的代码如何操作

1、点击录制宏

 

2、弹出我们要录制的宏定义,可以直接点击确定

 

3、我们删除一行代码,然后点“停止录制”

 

4、发现我们的代码里生成了一段这样的代码

Sub 宏2()

' 宏2 宏

    Rows("4:4").Select

    Selection.Delete Shift:=xlUp

End Sub

红色部分就是删除行的代码,可以解释为:删除第四行(从第四行到第四行)

5、这样我们就可以开发一个程序,把第一列单元格内容小于10的进行行删除。

先建立一个按钮,关联宏方法deleteRow()

Sub deleteRow()

    '从20行遍历到第1行(删除应该倒序遍历,因为index有变化)

    For i = 20 To 1 Step -1

        If Cells(i, 1) <= 10 Then

            '删除第i行

            Rows(i & ":" & i).Select

            Selection.Delete Shift:=xlUp

        End If

    Next i

End Sub

 

对象编程excel

主要类

VBA也把excel的各种控件分装成了对象,可以调用这些定义好的类、属性、方法操作控件。

这里的类、属性、方法与Java在概念上一致。

以下是调用操作excel常用的类:(当这些类被创建对象,每个对象就代表具体的excel相应控件)

Application :正在运行的excel系统本身

WorkBook :代表一个打开的excel文件也成为工作簿 (打开的一个excel文件就是一个工作簿)

WorkSheet :代表一张工作表,也是一个sheet页

Range :代表一个或多个单元格组成的内容区域。

因为一个application中有多个工作簿,一个工作簿(WorkBook)中有多个工作表

(WorkSheet),一个工作表包含多个单元格。

所以Application类里有一个属性是WorkBooks,他是一个集合,用来存放多个WrokBook。

WorkBook下也有一个属性,是一个集合,用来存放工作表,这个属性就是WorkSheets。

WorkSheet下也有一个属性,用来存放一个单元格对象,属性是Cells

 

WorkBook 

工作簿

Application 

Excel系统

WorkSheet

工作表

 

Range

单元格内容区域

多个单元格对象

WorkBooks

存放WorkBook的集合

 

WorkSheets

存放WorkSheet的集合

 

Cells

一个单元格个对象

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

使用类操作excel

1、定义一个变量,变量类型是WorkSheet,写法如下:

   Dim  w1  As  WorkSheet

2、给一个属于复杂类型的变量赋值,需要加关键字Set,写法如下:

   Set  w1 = WorkSheets(i);

例子:

Sub test1()

    '定义一个变量存放sheet对象

    Dim w1 As Worksheet

    Dim i

    '遍历所有sheet页

    For i = 1 To Worksheets.Count

        Set w1 = Worksheets(i)

        '让每个sheet页面的10行1列都等于自己的sheet名

        w1.Cells(10, 1) = w1.Name

    Next i

End Sub

新建一张工作表

WorkSheet的Add方法:在所属工作簿的文件中新建一个工作表(sheet页)

新建工作表例子代码:

Sub test2()

    '定义一个变量存放sheet对象

    Dim w1 As Worksheet

    '在本工作簿中新建一个sheet页

    Set w1 = Worksheets.Add

    '设定新建工作簿名

    w1.Name = "new sheet"

End Sub

获取工作表对象

1、按sheet页所在顺序取工作表对象:

例:取第二个sheet页

Dim w1 As Worksheet

Set w1 = Worksheets(2)

2、按sheet页名字取工作表对象

Dim w1 As Worksheet

Set w1 = Worksheets(“new test”)

 

过程(宏)调用

过程调用用Call关键字,例:

Sub test3()

    Dim w1 As Worksheet

    Set w1 = Worksheets.Add

    w1.Name = "new"

End Sub

 

Sub test4()

    '调用过程test3

    Call test3

End Sub

Call关键字可以省略

 

 

函数 Function

函数是过程的一种,在执行结束后能将运行结果返回给调用者

函数需要不用Sub关键字,用Function,函数追后一行写上:函数名 = 要返回的值

这样调用这个函数的过程可以通过变量接受这个函数。

 

函数可以在excel的单元格中当成公式使用

在单元格中可以写入公式:

 

 

系统常用函数:处理字符串函数

1、Len(str) 返回字符串长度

 

点三角箭头运行,弹出str字符串的长度

 

 

2、Trim(str) 去除两边空格

3、Replace(str,a,b)把字符串str中所有a都替换成b

4、Lcase(str) 所有英文字母都编程小写

   Ucase(str) 所有英文字母都编程大写

5、Left(str,3)把字符串str从左边取3个字符

   Right(str,3)把字符串str从右边取3个字符

6、Mid(str,2,5) 把字符串str从第二个字符开始,取五个字符

7、InStr(str,”a”) 在str中寻找a出现的位置,如果没找到返回0

   InStr(3,str,”a”) 在str中,从第3个字符开始寻找a出现的位置

For Each

 

 

操作多个excel文件()

1、WorkBooks.open(文件名) 指定路径打开excel文件

 

2、Close关闭操作的工作簿

上例代码最后加入如下代码:

wb.Close

3、新建一个工作簿

WorkBooks.Add

 

Range单元格对象

Cells是定位单元格用的,并不是单元格对象,单元格对象类是Range

Cells的写法是我们平时的简写,如果写全应该是如下格式:

                

1、Range属性

返回任意单元格范围:Range(“D5”) , Range(“B3 : F7”)

 

也可以用下面方法定位左上角和右下角位置,定位到单元格范围:

 

2、修改Range范围内单元格内容

     

3、清除范围内单元格内容

 

例子代码:

 

4、Range的Font属性

 

还有color 字体颜色 Bold字体粗细 等属性

例子代码:

 

5、Range.Interior属性:

 

6、clear清除

 

7、Range.Merge合并单元格:将Range范围内单元格合并为一个单元格

   Range.UnMerge拆分单元格: 将Range范围内单元格拆分为一个个单元格

合并共同前缀代码 with

 

以上代码可以用with改写为下面的代码:

 

Application对象

1、默认直接调用的属性是Application的属性

代码中我们控制一个单元格常常这么写:

Cells(3,5) = “text”

那么Cells是谁的属性呢?如果我们用以下写法:

Dim  w  As  Worksheet

Set  w  = Worksheets(1)

w.Cells(3,5) = “text”

那么我们知道Cells是Worksheet的属性,而直接写Cells,那么他是Application的属性

等同于:

Application.Cells(3,5)=”test”

Application代表所有打开的excel工作表里,当前正在被我们编辑的工作表(sheet),也可以理解为当前正在显示的工作表。Application可以默认不写。

同理直接调用的这个代码:Range(“E3”)=7,这个Range属性也是Application下的属性。

 

2、Application.ActiveWorkbook:

当前正处于激活状态的工作簿(即活动工作簿)对象

 

3、Application.ActiveSheet:

当前正处于激活状态的工作表(即活动工作表)对象

 

例:记录我们当前工作簿的对象,在操作变化后,能找到当初的对象

Dim w1 As Workbook, w1 As Wrokbook

Set w1 = Application.ActiveWorkbook

Set w2 = Workbooks.Add

w2.Wroksheets(1).Cells(2,2) =”a”;    ‘操作新建工作簿的第一个工作表的2行2列单元格个

w1.Wroksheet(1).Cells(3,5) = “b”    ‘操作当初工作簿第一个工作表的3行5列单元格个

以上这个代码的功能就是利用Application记住了当初的操作文件,即使操作其他文件后,也能够找到原来的操作文件。

4、Application.WorksheetFunction.公式名:

在VBA代码中直接调用Excel表格公式

例如:获取B2到D7单元格中最大的值

M = Application.WorksheetFunction.Max(Range(“B2:D7”))

也可以写成:

Set r = Range(Cells(2,2),Cells(7,4))

M = Application.WorksheetFunction.Max(r)

5、Application.DisplayAlerts

是否显示Excel警告框。

例如保存一个文件代码如下:

W2.SaveAs(“xxx.xlsx”)

W2.Close

执行第一次,很自然生成了一个xxx.xlsx文件保存到当前目录,但是再执行这个程序,每次都提示是否覆盖,用Application可以关闭这个提示,直接覆盖。

在代码中写入:Application.DisplayAlerts = false

再执行保存文件代码,文件直接覆盖,不再提示是否覆盖。

记得操作完后,在调用close后,一定要再让Application.DisplayAlerts = true,

否者excel任何操作都不在弹出提示信息。

6、Application.quit

退出excel

 

VBA笔记进阶篇

数据类型

常用类型

字符型:Dim str As String

              str = “TEST”

整数型:Dim strLen As Integer

              strLen = 3

变体型:不定义类型,根据赋值的数据类型定义类型(可以调整赋值来变化数据类型)

Dim str

        str = “TEST”

变体类型缺点:

1、效率低,速度慢,因为程序每次都要判断这个数据是什么类型

2、一旦单元格被设置成文本类型,从单元格抓取数据,会把数字型当成字符型处理

 

注意:Dim a ,b As String  a是变体类型,b是整数型

Dim a As Integer, b As String   a 和 b 都是整数型

+ 和 & 的 区别

加号只能链接两边都是字符串的数据,而&可以连接字符型也可以连接数字型

其他类型:

Integer:占用内存2字节,不支持小数,取值范围:-32768 到 + 32768

Long:占用内存4字节,不支持小数,取值范围:-2147483648到 + 2147483648

      循环工作表最好用Long类型数据

Double:占用内存8字节,支持小数,有误差

Currency:占用内存8字节,支持小数,固定4位小数,数据精确。

特殊符号代表数据类型

1、特殊符号代表数据类型

Dim result As Long

Result = 30000 * 3

上面这两行代码会报错,因为30000*3的结果会存放到临时空间然后再赋值给result,即使result是Long型,能装下这个结果,但是临时空间是Integer,所以临时空间报错。之所以临时空间是Integer型,是因为30000和3都是Integer型数据,所以临时空间会变为Integer型。所以我们需要让临时空间知道30000需要定义成Long型,写法如下:

Dim result As Long

Result = 30000& * 3

 

Dim a&, b# 等价于 Dim a As Long ,b As Double

所以&作为连接符号的时候必须与左右两边留有空格,否者会被当成Long类型

2、下划线:

把很长的语句拆分成若干行书写

 

3、冒号

把很多行语句拼接到同一行,不浪费空间,代码整洁。

a1 = Cells(1, 1): a2 = Cells(1, 2): a3 = Cells(1, 3)

4、^  幂运算

a的6次方   a ^ 6

5、 \  只保留整数部分的除法符号

日期型

 

例:日期格式默认 月日年 时分秒,日期两边要有#,声明式日期

    Dim d1 As Date

    d1 = #1/19/2016 10:10:01 AM#

    MsgBox d1

1、Date函数 显示日期

Dim d1 As Date

    d1 = Date

MsgBox d1

2、Time()函数 显示时分秒

3、Now()函数 显示日期+时间

4、解析时间

 

 

5、DateDiff函数

 

 

6、DateAdd函数

 

注意:

日期型本质上就式一个Double型的数字,0代表1899年12月30日0时0分0秒

整数部分增减1就式增减1天,小数部分0.1代表0.1天,即2.4小时。

 

逻辑类型 Boolean

只返回True和False

 

逻辑关系运算符:

AND 并且  相当于Java的 &&

OR   或则  相当于Java的 ||

NOT  非    相当于Java的 !

其他

流程控制:

Do While 用法补充

靠条件控制,不再进行下一次循环

 

Exit语句

直接跳出一个循环结构或一个子过程(函数),

比如退出Do While循环,可以写做Exit Do

如果是结束for循环就是 Exit For,退出函数用 Exit Sub

用Exit退出,Exit下面的代码将不再执行

注意:

1、Do While 可以用Exit Do结束循环,While无法使用Exit结束循环,所以处理循环不要用While

2、Exit 和Java中的break一样,当用在嵌套循环中,只能结束当前这个循环,不能结束所有循环。

GoTo 语句

直接跳转到指定标签位置:

 

因为GoTo语句太过随意,容易造成代码混乱,不建议使用,只建议在处理异常中使用,如下节

On Error GoTo MyError

这个语句的意思是:从下一句开始,一旦发生错误就直接跳转到MyError标签处继续运行

 

On Error Resume Next

从下面开始,如果某行运行错误,就忽略它并继续执行

 

函数

IsDate

验证数据是否是日期型,是日期型返回True

例如:验证单元格1行1列是否是日期型:

If IsDate(Cells(1,1)) = True Then

       Cells(1,1) = DataAdd(“d”,38, Cells(1,1))

End If

IsNumeric

如果x是某种数值类型,比如Integer,Long,Single,Double,Currency等,函数返回True,如果是其他类型返回False。

 

TypeName

返回数据类型的类名

例如:TypeName(“test”) 返回String字符串

数据类型的转换函数

Cbool,Cdate,CStr,Cint,CLng,CDbl,Ccur,Csng,Cbyte,Cdec

 

 

VBA中可以自动类型转换,不加这些转换函数也可以,但是加了会让代码更加清晰。

如果Double转换成Integer会进行四舍五入,到那时他的这个四舍五入规则与我们的不同,用的是银行家舍入法:

 

Excel工作表中只能存放1900年以后的日期,如果想存放更之前的日期就需要用Cstr把日期型转换成字符型,然后存放到excel中。

四舍五入函数

VBA中的Round(x,n)也是用的银行家舍入法,对x进行四舍五入,并保留小数点后n位数字。

如果想使用我们平时用的规则,需要用excel中的公式:

Application.WorksheetFunction.Round(x,2)

Int(x)

如果不是excel文件中没有上面这个函数我们可以用Int()函数帮忙实现四舍五入的功能

Int(x)函数,返回一个不大于x的最大整数,例如:

 

所以用如下这个公式就可以实现四舍五入:

       i = Int(x+0.5)

负数的四舍五入规则不一,本方法将-2.5舍入为-2,所以需要根据业务来确定是否符合规定

Asc和Chr

Asc(“A”)  把字符A转换成ASCII码

Chr(65)   把ASCII码转换成对应字符

所有的字符都可以转换成数字来表示,ASCII就是一种编码格式。

所以字符和数字可以靠上面的两个函数来回转换

用途:

1、如果需要在字符串中加入换行符,就需要用到上面的函数。例:

 Str = “xxxxxxxxxxxxxxxxxx” & Chr(13) & Chr(10) & “xxxxxxxxxxxxxxxxxxx”

 

2、如果想把a到z打印到excel中,可以使用如下写法:

For i=65 To 90

       Cells(i-63,2) = Chr(i)

Next i

我们想把数字转换成对应的字母,都可以用Char函数解决

 

3、比较字符大小,可以读取字符的每一个字母,用Asc函数转换成ASCII码,然后比较大小。

ASCII码转换表:

 

数组 Array

定义一个数组变量:Dim my_arr(9) As String

解释:

1、变量后面带括号代表是数组类型,括号里放数组最大下标,

2、数组下标从0开始,这里会放10个数

3、字符型数组

例:

 

自定义数组下标:

Dim arr (3 To 6)

让变体(因为这里没指定数组类型 )数组arr的最小下标为3,最大为6,改数组的元素包括 a(3) a(4) a(5) a(6)

Lbound(arr)返回数组最小下标

Ubound(arr)返回数组最大小标

以上两个函数的结果可以给for循环数组开始接受位置用

Split函数

Split(待拆分的字符串,分割符字符串)

将字符串按照指定分隔符拆分成多个字串,返回一个数组

Dim arr() As String

arr=Split(Cells(1,1),”,”)

 

For Each 循环

下面x代表数组每一个元素,a是数组

       For Each x In a

              str = x

       Next x

 

 

文本处理

读取文本文件

VBA读取文件流程

1、打开文件

Open “d:\demo\client.text” For Input As #1

For Input 代表输入。#1代表代号,这个被打开文件的代号。

2、读取一行内容

Line Input #1,s (读取#1代表的文件一行记录,每执行一次这句代码就会读取一行,执行几次读取几行)

3、是否已读取到末尾

EOF(1) 读取#1代表的文件,如果读取到末尾这个函数返回True

4、关闭文件

Close #1  关闭#1代表的文件

例:

 

写入文本文件:

1、打开写入文本文件

Open “d:\demo\client.text” For Output As #1

写入一个文件,如果有同名文件会覆盖,没有此文件会创建

Open “d:\demo\client.text” For Sppend As #1

追加内容写入文件,不会覆盖原文件内容

2、写入一行

Print  #1  “xxxxx”;   莫非带分号,再次写入,同行追加

Print  #1  “xxxxx”   末尾空白,再次写入,字符会换行

3、关闭文件

Close #1

Dir函数读取目录所有文件

读取目录下所有文件

打开一个目录,目录结尾必须是“\”,f是返回的一个文件名

f = Dir("c:\testfile\")

然后每执行一次f = Dir都返回一个目录下的文件名

Sub test8()

   Dim f As String

   f = Dir("c:\testfile\")

   Do While f <> ""

       MsgBox f   ‘弹出文件名

       f = Dir      ‘读取下一个文件名

   Loop

End Sub

 

打开一个目录下所有excel文件转换成Wrokbooks对象:

Set w = Wrokbooks.Open(path & fileName)

 

读取指定文件

只想打开xlsx结尾的文件:

用这个判断语句 If Lcase(Right(fileName,5)) = “.xlsx”

更高级的写法:

fileName = Dir(“d:\test\*.xlsx”)

判断目录是否存在                                

判断文件是否存在

Dir(“目录文件名”)返回空字符串证明没有这个文件

返回目录和子目录下所有文件名:

只返回一层子目录

f = Dir(“D:\test\”,”vbDirectory”)

返回目录下所有文件和所有子目录文件

需要用到递归方法

判断是文件夹:

GetAttr(“file dir”) And vbDirectory = vbDirectory

 

 

Range对象高级使用

Range代表单元格区域对象 (可以理解为单元格二维数组)

Range对象位置有关属性:

1、Range.Row 该Range左上角单元格的行号

2、Range.Column 该Range左上角单元格的列号

3、Range.Address该Range各个对焦顶点的绝对引用地址。

Set r = Range(“B3:D9”)    r.Address返回“$B$3:$D$9”

注意:

当Range包含多个矩形区域时,Row和Column只返回其中某一个矩形的左上角位置,并不一定是整个Range的左上角。

比如Range(“D3:E4,A1:B2”)的Row和Column返回的可能是第3行第4列,而非第一行第一列

Range对象范围有关的属性:

1、Range.Count 该Range中的单元格数量

注意:Range对象由多个矩形区域构成时,个矩形相互重叠的单元格会被重复计算。

      Count计算的其实是对象而非单元格个数,而且当数量太大时会发生溢出错误,所以计算单元格格最安全的方法是Range.Cells.CountLarge

2、Range.Rows 容纳了该Range中的每一行,可以使用Range.Rows(n)得到一个新的Range对象,代表该区域第n行的所有单元格。

注意:如果Range是由多个矩形区域构成,Rows只代表其中某一个矩形区域的所有行。

例子:Set a = Range(“C4:E12”)

      a.Select  ‘将Range对象全部选中(方便看现象)

      Set rw = a.Rows(2)  ‘把Range中的第二行全部取出,rw对象还是一个Range    

3、Range.Columns 容纳了该Range中的每一列,可以使用Range.Columns(n)得到一个新的Range对象,代表位于该区域第n列的所有单元格。

4、Range.Cells(1,1) 取Range范围内的第一行第一列单元格

特殊的Range对象

1、代表工作表(sheet)中全部单元格的对象

WorkSheet的属性Cells

取得最大行号:ActiveSheet.Cells.Rows.Count

2代表工作表(sheet)中全部被使用过的单元格(有效单元格,包含所有数据)Range对象

WorkSheet的UsedRange属性

返回一个矩形区域的Range对象,正好能够容纳这个工作表中所有使用过的单元格。

注:即使一个单元格修改过格式没有填写内容也会被认为是被使用过,有些情况下单元格内容被删除清空后仍可能被认为是使用过的。

例子代码:把使用过的单元格选中

 

获取该行最后一行的行号:r.Row + r.Rows.Count -1 (左上角起始行号+Range范围行数-1)

Range转化二维数组(提高读写excel效率)

如果我们的表格中有大量的单元格要读取,用平时我们用的Cells一个个单元格个读取效率将会非常低下,所以我们可以把要读取的单元格范围(Range)转化成二维数组,然后读取数组获得内容。

二维数组 Dim arr(3,5) As Long  有4行6列个元素(起始位置从0开始)

如果只想二维数组返回三行五列并且从1开始,可以写成

Dim arr(1 To 3, 1 To 5) As Long

Ubound(arr,1)  二维数组第1行数据的最大下标

Lbound(arr,1)  二维数组第1行数据的最小下标

把Range对象转换为二维数组的写法

Dim arr()

arr=Range(“A2:C3”)

注意:Range转换成二维数组,数组的下标是从1开始(与Cells的下标规则一样)

例:

 

1、如果读取的范围操作Range的返回会发生下标越界错误

2、截取Range的数组,声明的时候必须是动态数组(数组后面的括号里不写下标范围)

3、这个数组必须是变体类型,不能声明成具体数据类型。

4、Range中即使只有一行数据,转化成数组后也是二维数组,是一个1行多列的二位数组。

把数组写入Range中

Dim s(2,3) As Integer

S(0,0)=1 : S(0,1)=2: S(0,2)=3: S(1,0)=4 : S(1,0)=5: S(1,0)=6

Range(“b2:e4”) = s

 

 

 

如果想把一个维数组放到execel的一列中,需要使用矩阵转置函数

Range(“c2:f2”) = Application.Transpose(s)

遍历Range

Range的结构可以理解成一个二维数组的结构,我们可以用双重循环遍历Range,如果我们不关心Range每个单元格的具体行号,只是单纯的遍历处理,那么我们可以用Each方式遍历Range的每一个单元格。

例:取出所有被使用的单元格,单元格个内容是红色的相加

Dim r As Range,r1 As Range

Set r = w.UsedRange ‘取出所有被使用的单元格

For Each r1 In r

       If r1.Font.Color = vbRed Then

              s = s + r1.Value

       End If

Next r1

拆分成两个处理:(调用函数)

 

 

Range.HasFormula属性

当Range是一个单元格时,此属性查看单元格中是否有公式,由公式这个属性返回True,没有返回False

Range.Formula属性

当Range是一个单元格时,如果单元格是公式则返回公式文本,如果没有公式则与Value属性一样返回单元格的内容。

Range的Value属性,如果单元格是公式,Value返回的是公式的结果

如果想把一个单元格设置成一个公式,Formula和Value都可以:

 

Range的下标

当我们得到一个Range对象,要遍历Range的对象的时候下标是从1开始,无论这个Range的单元格在sheet中的什么位置。而Cells读取单元格的下标都是根据单元格相对于sheet中位置定的,必须是从sheet的1,1开始。

所以遍历Range,定义范围可以用如下方法

 

Application.Union方法

把多个Range对象联合成一个新的Range对象

Dim r As Range

Set r = Union(Range(a1:b2), Range(c1:d2), Range(e1:f2))

但是Range的区域如果有重合,新合并的Range会有重复单元格

Application.Intersect方法

找到同时属于多个Range的单元格(各Range重合的部分),作为一个新的Range对象返回。下图紫色部分就是找出的重合部分

 

Range.CurrentRegion属性

返回一个包含了这个Range的最大连续使用区域。该区域与其他任何已使用单元格都不邻接。如下图通过蓝色部分找到蓝色区域所在表的所有单元格对象,返回一个Range对象。

 

例子:找到有“上海市”这几个字的单元格,把这个单元格所在的表变色

 

Range.Resize属性:

以该当前Range的左上角单元格为原点,生成一个指定大小的新的Range对象并返回。

 

上面两句可以合并写成:

Range.Offset属性

按照Range的大小,根据指定的距离平行移动,从而得到一个新的同形状的Range。

 

Range.Rows与Worksheets.Rows (Columns)

选中Range的第一行数据

    Dim r As Range

    Set r = Range("A1:H100")

r.Rows(1).Select

选中当前sheet页的第二行数据

    Dim r As Range

    Set r = ActiveSheet.Rows(2)

    r.Rows(1).Select

Range.Rows与Worksheets.Rows均可以一次返回多行或多列,例如

Rows(“2:3”)  返回第二行和第三行,返回的结果还是Range

Columns(“B:E”)返回B列到E列,返回的结果还是Range

合并单元格

如果D6到E7已经合并单元格,我们用For Each遍历这个Range对象

 

我们会发现他程序还是遍历了4次,而不是一次,程序还是认为Range中有4格单元格。但是只有第一个单元格D6有数据(合并单元格中的数据),其他单元格都没有数据。

结论:

1、多个单元格合并之后,仍被VBA认为是各自独立的单元格

2、第一个单元格的值为合并后显示的内容,其他单元格被认为是空值

Range.MergeCells属性

1、当该Range完全合并为一个单元格时,该属性为True

2、当该Range完全不包含合并单元格时,该属性为False

例如上例:Range(“d6:e7”).MergeCells = True

3、当该Range中有合并单元格,还有一部分没合并单元格,返回NULL

判断是否为Null的时候要用IsNull函数

 

4、把一个Range对象合并单元格:

Range(“A1:B3”).MergeCells = True

同理,解除合并单元格:

Range(“A1:B3”).MergeCells = False

5、VBA还提供了合并和取消合并单元格的方法。

Range.Merge合并单元格  例: Range(“A1:B3”).Merge

Range.UnMerge 取消合并单元格Range(“A1:B3”).UnMerge

Range(“A1:B3”).Merge True这个写法是按行合并单元格

Select

Range(“A1:B3”).Select

让这个Range的对象都被选中(和被鼠标选中效果一致)

Dim r As Range

Set r = Selection  

获取鼠标选中的单元格,返回一个Range对象

可以根据录制宏查看复制、剪切、添加等功能,结合鼠标选中(Select),做出很多操作excel的功能。

注意:尽量不要用Select获取Range对象,影响性能。可以用Cells()等方法代替Select

提高VBA代码的性能:

1、极可能合并不必要的Select和Selection

2、尽可能删除不必要的属性设置

3、尽可能减少对象中“.”的数量,用With消减“.”的调用

 

函数的高级使用技巧

可选参数

1、Optional  指定一个可选参数

Function mySumProduct(r As Rage, Optional useColumn As Boolean=False)

在调用此函数的时候,可以不写这个参数,不写这个参数默认False

IsMissing(a)函数

判断一个可选参数a是否被提供,如果没有提供,则返回True,否则返回False

要求:该可选参数必须是变体类型,且不能有默认值。

例子代码:

 

 

myFun(3, ,5)这个写法是只传递第一个和第二个参数。另外还有一个更好的调用方法

2、指定参数名传递参数

使用 := 可以按参数名传递参数数值

如上例可以写成:myFun(a:=3, c:=5)

Msgbox函数

我们常用的Msgbox(弹出对话框)就是一个可选参数

Msgbox “信息!” , 1 

第二个参数就是弹出画面的种类,只有确认按钮,有确认和取消按钮等

 

这些数字在VBA中有对应的常量,例如:

Msgbox “信息!” , 1   等价于 Msgbox “信息!” , vbYesNo

 

Msgbox还有第三个可选参数,是显示titile信息用的

 

Msgbox的返回值:

i=MsgBox(“please button”,vbYesNo)

在弹出的对话框上选yes,i返回6,选no,i返回7

 

函数后面的参数写不写在括号里:

调用函数决定是否写括号的三种情况:

1、没有参数:不写

2、有参数,调用语句处于一行代码中间:写

例1:      x = myFun(3,4,5)

例2:      If m myFun(3,4,5) >10 Then

3、有参数,调用语句独占一行代码:不写

例:  Sub demo()

              myFun 3, 5, 7

       End Sub

之所以一行Function,不写括号是因为程序会把这个代码当成eval计算(同js的eval方法)

 

VBA对象的默认属性

 

4、如果记不住以上规则,可以在调用函数的时候加Call

Call mySub(3,5,7)

值传递和引用传递:

ByRef

VBA在默认情况下都是引用传递,如果把一个变量a传递给一个函数,函数对a进行了更改,函数结束后,a变量的值也会跟谁更改,因为VBA是把a这个对象传递给了函数。

ByVal

如果想让VBA值传递(也就是只把值传递给函数,函数即使修改了参数的值,也不会影响函数外面的变量)代码写法:Sub 过程名(ByVal a As Integer)

 

Set

想把一个对象赋值给一个变量必须要用Set,想把一个基本类型赋值给一个变量就不用加Set

例如: Set w = Worksheets(1)

       i = 5

以上就是VBA的默认属性导致

Cells(3,2)的默认属性是Value,所以我们想给这个单元格赋值的时候可以直接写Cells(3,2)=1。

当我们写 r = Cells(3,2)的时候,VBA不知道你是想把这个cells的Value赋值给r,还是想把这个cells对象赋值给r。所以对象型赋值要用Set标记。

模运算MOD

MOD相当于java的%,求余数用

i=7 MOD 4 结果是3 

随机函数 Random

 

取0 1 2 3的随机数: i=Int(Rnd()*4)

 

生成a到b之间的随机整数公式:int(Rnd()*(b-a+1)+a)

Rnd()计算的是一个伪随机数

 

生成没有规律的随机数需要如下操作:

 

事件处理

常用事件

 

用户在Excel中的一个操作,或者Excel系统自身的一个变化,都可以被视作一个“事件”。Excel会随时监听这些事件,并可以根据编码的要求,在某个事件发生时自动运行对应的VBA程序。

事件发生在哪里,代码就要写在哪里,如果事件是靠工作簿触发,事件代码就要写到工作簿文件中。

    打开对应文件后,要起固定的方法名,例如想workbook一打开就触发事件,就要把代码写到ThisWorkbook这个文件里,而且方法名要叫 workbook_open()

 

 

 

 

如下图,在文件中选中Worksheet,在右边就能看到所有对应sheet的事件名称。

 

工作簿常用事件

新增工作表(sheet)触发的事件用Workbook_NewSheet,sh这个参数代表刚刚新建的工作表。

 

例子代码:

新建一个工作表就自动在新建的工作表上增加一个表格:

 

这样没新建一个工作表,就会生成如下表格:

 

工作表常用事件

SelectionChange事件,每当用户选中一个新的单元格时,Selection_Change事件就会被触发。这个事件带有一个参数Target,代表刚刚被选中的单元格对象/区域。

例如:没选中一个单元格,就弹出这个单元格的坐标。

 

利用Range的属性:

Range.EntireRow   Range所在单元格的整个行

Range.EntireColumn   Range所在单元格的整个列

做一个功能鼠标选中这个单元格,单元格的所在行和所在列都改变颜色

 

效果如下,鼠标选中哪个单元格,单元格所在行和列都变为天蓝色。

 

注意:这个事件写在哪个sheet里,就哪个sheet页有这个事件,而不是所有sheet页都有这个事件。

Sheet事件文件与excel的sheet页一一对应,见下图:

 

所以多个sheet页都想要同一个事件效果,需要把实现效果的代码写在模块里,写一个子过程,然后每个sheet页都调用这个子过程就可以了。

作用域

变量和过程(函数)都有作用域

Private 只能被本模块内部的代码调用。

Public 可以被其他模块的代码调用。

子过程和函数如果指明,默认为Public

变量若不指明,默认为Private

例如:

Private Function test()

       …

End Function

Private Sub Test2()

       …

End Sub

防止事件级联

Worksheet_Change(Target)

工作表事件,修改单元格内容,焦点离开,会触发。(没修改单元格内容也会触发)

 

如果我们在change事件发生后又修改了单元格内容,这样的操作又会触发change事件,然后就引发了事件级联,避免发生的办法如下:

 

下面例子是用Application.EnableEvents=False方法解决级联效应

 

你可能感兴趣的:(windows,excel)