过程是一个VBA语句块,包含在声明语句(Function、Sub、Get和Set)和匹配的End声明中。
VBA中的所有可执行语句都必须位于某个过程内。可以将整个应用程度编写为单个大的过程,但如果将它分解为多个较小的过程,代码就更容易阅读和理解。
1 VBA过程类型
1.1 VBA子过程:用于执行代码后不返回值的情况。它们以关键字Sub开头,并以关键字End Sub结束。在Excel中录制的宏就是这种过程。
1.2 Function函数过程:用于执行代码后返回计算结果的情况。它们以关键字Function开头,以关键字End Function结束。使用Function函数过程可创建Excel的扩展函数。
1.3 Property过程:用于自定义对象。使用属性过程可设置和获取对象属性的值,或者设置对另外一个对象的引用。
2 VBA子过程与Function函数过程的区别
2.1 Sub子过程不能返回值,而Function函数过程可以返回一个值,因此可以像Excel内部函数一样在表达式中使用Function函数。
2.2 Sub过程可作为Excel中的宏来调用,而Function函数不会出现在“选择宏”对话框中,如果要在工作表中调用Function函数,则可以像使用Excel内部函数一样使用该函数。
2.3 在VBA中,Sub过程可作为独立的基本语句调用,而Function函数通常作为表达式的一部分。
3 Sub过程结构
[Private | Public | Friend] [Static] Sub 过程名 [(参数列表)]
[语句序列1]
[Exit Sub]
[语句序列2]
End Sub
如:
Sub 手工创建Sub过程()
MsgBox "这是手工输入代码创建的Sub过程!"
End Sub
4 Function函数的语法结构
[Private | Public | Friend] [Static] Function 函数名 [(参数列表)] [As 返回类型]
[语句序列1]
[函数名=表达式1]
[Exit Function]
[语句序列2]
[函数名=表达式2]
End Sub
如:
Function fTest1(a As Integer, b As Integer) As Integer
Dim t As Integer
Randomize
If a > b Then
t = a
a = b
b = t
End If
fTest1 = Int(Rnd * (b - a)) + a
End Function
5 Sub子过程调用
5.1 用Call语句调用
Call 过程名(过程参数列表) ‘没有参数,可以写成:Call 过程名
5.2 将过程作为一个语句
Call Test(a,b)
或
Call Test a, b
6 调用Function函数过程
6.1 在工作表的公式中调用
“公式”选项卡→“插入函数”→在”或选择类别“选择框内选择”用户定义“,即可看到自定义的函数,如下:
6.2 在VBA代码中调用
在VBA代码中,可以像VBA内部函数一样调用这种用户自定义的Function函数。
Sub 生成随机数()
Dim R As Integer, l As Integer, u As Integer
l = Val(InputBox("请输入随机数的下限:", "设置下限", 1))
u = Val(InputBox("请输入随机数的上限:", "设置上限", 100))
R = fTest1(l, u)
MsgBox "生成的随机数为:" & R
End Sub
7 过程参数的形参与实参结合的方式
7.1 按位置结合
Function fTest1(a As Integer, b As Integer) As Integer
...End Function
Call fTest1(1,100)
7.2 按命名参数方式结合
Call fTest1(a:=1,b:=100) '两个参数的位置可以随意
7.3 按位置和名称混合结合参数
Call fTest1(1,b:=100)
8 过程参数传递方式(传值或传地址)
在VBA中,实参可通过传值和传地址两种方式将数据传递给形参。
定义过程时,在形参的前面添加ByVal关键字,则该参数就按传值方式传递;否则就按传地址(默认)方式传递。
8.1 按传值方式传递参数
Sub 传值测试(ByVal a As Integer)
a = a + 1
Debug.Print "子过程中的变量A=" & a
End Sub
Sub 调用传值测试()
Dim b As Integer
b = 3
Debug.Print "主程序中变量B=" & b
传值测试 b
Debug.Print "主程序中变量B=" & b
End Sub
上述代码在“立即窗口”中的显示结果:
主程序中变量B=3
子过程中的变量A=4
主程序中变量B=3
由上面的结果可知,值并没有真正传递过去。
8.2 按传地址方式传递参数
Sub 传地址测试(ByRef a As Integer)
a = a + 1
Debug.Print "子过程中的变量A=" & a
End Sub
Sub 调用传地址过程()
Dim b As Integer
b = 3
Debug.Print "主程序中变量B=" & b
传地址测试 b
Debug.Print "主程序中变量B=" & b
End Sub
上述代码在“立即窗口”中的显示结果:
主程序中变量B=3
子过程中的变量A=4
主程序中变量B=4
9 数组作为参数
Sub 求最大数(a() As Integer)
Dim i As Integer, max As Integer
max = a(LBound(a))
For i = LBound(a) To UBound(a)
If a(i) > max Then max = a(i)
Next
Debug.Print "最大数:" & max
End Sub
Sub 测试求最大数()
Dim MyArray(5) As Integer, i As Integer
For i = 0 To 5
MyArray(i) = i * 2
Next
求最大数 MyArray()
End Sub
10 设置可选参数
“可选参数”在过程定义中由关键字Optional指示:
Sub 可选参数(strName As String, strSex As String, Optional ID)
With Worksheets("sheet3")
.Range("A2") = strName
.Range("B2") = strSex
If Not IsMissing(ID) Then
.Range("C2") = ID
End If
End With
End Sub
Public Sub 调用可选参数过程1()
可选参数 "wwu", "male"
End Sub
Public Sub 调用可选参数过程1()
可选参数 "wwu", "male", "2012"
End Sub
11 设置可变参数
“可变参数”在过程定义中由关键字ParamArray和一个Variant数组定义:
Sub MySum(intTotal As Integer, ParamArray intNum())
Dim i As Integer, j As Integer
For i = LBound(intNum) To UBound(intNum)
intTotal = intTotal + intNum(i)
Next
End Sub
Sub 调用可变参数()
Dim i As Integer
MySum i, 1, 2, 3, 4, 5, 6, 7, 8
Debug.Print i
End Sub
12 过程的递归调用
“递归”过程是指调用自身的过程。在递归调用中,一个过程执行的某一步要用到它自身的上一步(或上几步)的结果。
Function fact(ByVal n As Integer) As Long
If n <= 1 Then
fact = 1
Else
fact = fact(n - 1) * n
End If
End Function
Sub test()
Debug.Print fact(8)
End Sub
13 常用过程实例
13.1 计算个人所得税
个人所得税税率表(3500起征) | |||
级数 | 全月应纳税所得额 | 税率 | 速算扣除数(元) |
1 | 全月应纳税额不超过1500元 | 3% | 0 |
2 | 全月应纳税额超过1500元至4500元 | 10% | 105 |
3 | 全月应纳税额超过4500元至9000元 | 20% | 555 |
4 | 全月应纳税额超过9000元至35000元 | 25% | 1005 |
5 | 全月应纳税额超过35000元至55000元 | 30% | 2755 |
6 | 全月应纳税额超过55000元至80000元 | 35% | 5505 |
7 | 全月应纳税额超过80000元 | 45% | 13505 |
Public Function taxes(curP As Currency, Optional dep As Integer = 3500)
Dim curT As Currency
curP = curP - dep '3500为扣除数
If curP > 0 Then
Select Case curP
Case Is <= 1500
curT = curP * 0.03
Case Is <= 4500
curT = curP * 0.1 - 105
Case Is <= 9000
curT = curP * 0.2 - 555
Case Is <= 35000
curT = curP * 0.25 - 1005
Case Is <= 55000
curT = curP * 0.3 - 2755
Case Is < 80000
curT = curP * 0.35 - 5505
Case Else
curT = curP * 0.45 - 13505
End Select
taxes = curT
Else
taxes = 0
End If
End Function
公式 | 对应值 |
=taxes(4000) | 15 |
=taxes(7000) | 245 |
=taxes(4000,5000) | 0 |
=taxes(7000,5000) | 95 |
13.2 将数值转换为表格的列号
Public Function NumtoCol(Numbers As Integer) As String
Dim i1 As Integer, i2 As Integer, i3 As Integer
Dim s1 As String, s2 As String, s3 As String
i2 = Numbers \ 26
i3 = i2 \ 26 '第3位
i2 = i2 Mod 26 '第2位
i1 = Numbers Mod 26 '第1位
If i2 > 0 And i1 = 0 Then
i1 = 26
i2 = i2 - 1
End If
If i3 > 0 And i2 = 0 Then
i2 = 26
i3 = i3 - 1
End If
s3 = Chr(i3 + 64)
s2 = Chr(i2 + 64)
s1 = Chr(i1 + 64)
If s3 = "@" Then
If s2 = "@" Then
NumtoCol = s1
Else
NumtoCol = s2 & s1
End If
Else
NumtoCol = s3 & s2 & s1
End If
End Function
Sub 显示列号()
With Worksheets("sheet1")
.Activate
.Range("AZ1").Select
End With
MsgBox Selection.Column
End Sub
Sub 测试显示列号()
Dim intCol As Integer
intCol = Val(InputBox("请输入列号(1~16384):"))
If intCol < 1 Or intCol > 16384 Then
MsgBox "输入的数据超过范围,请重新输入!"
Exit Sub
End If
MsgBox "列号:" & intCol & ",对应的字母为:" & NumtoCol(intCol)
End Sub
13.3 大写金额转换函数
Function CapsMoney(curMoney As Currency) As String '转换中文大写金额函数
Dim curMoney1 As Long
Dim i1 As Long '保存整数部分(元部分)
Dim i2 As Integer '保存十分位(角部分)
Dim i3 As Integer '保存百分位(分部分)
Dim s1 As String, s2 As String, s3 As String '保存转换后的字符串
curMoney1 = Round(curMoney * 100) '将金额扩大100倍,并进行四舍五入
i1 = Int(curMoney1 / 100) '获取元部分
i2 = Int(curMoney1 / 10) - i1 * 10 '获取角部分
i3 = curMoney1 - i1 * 100 - i2 * 10 '获取分部分
s1 = Application.WorksheetFunction.Text(i1, "[dbnum2]")
'将元部分转为中文大写
s2 = Application.WorksheetFunction.Text(i2, "[dbnum2]")
'将角部分转为中文大写
s3 = Application.WorksheetFunction.Text(i3, "[dbnum2]")
'将分部分转为中文大写
s1 = s1 & "元" '整数部分
If i3 <> 0 And i2 <> 0 Then '分和角都不为0
s1 = s1 & s2 & "角" & s3 & "分"
If i1 = 0 Then '元部分为0
s1 = s2 & "角" & s3 & "分"
End If
End If
If i3 = 0 And i2 <> 0 Then '分为0,角不为0
s1 = s1 & s2 & "角整"
If i1 = 0 Then '元部分为0
s1 = s2 & "角整"
End If
End If
If i3 <> 0 And i2 = 0 Then '分不为0,角为0
s1 = s1 & s2 & s3 & "分"
If i1 = 0 Then '元为0
s1 = s3 & "分"
End If
End If
If Right(s1, 1) = "元" Then s1 = s1 & "整" '为"元"后加上一个"整"字
CapsMoney = s1
End Function
-End-