Case Is <100000
curTemp = (curPay1-60000)*0.4+10375
Case Else
curTemp = (curPay1-100000)*0.45+15375
End Select
计算个人所得税 = curTemp
End Function
在使用Is关键字进行条件判断时,条件的先后顺序很重要。如本例中,若将Is<100000写在第一个条件位置,程序运行将得不到正确的结果。
7.3.6 分支结构的嵌套
在一个分支结构语句中还可以包含另一个分支结构语句,这称为嵌套。例如,以下程序用于判断当前单元格中保存值的类型:
Sub 判断当前单元格数据类型()
If IsEmpty(ActiveCell) Then '单元格为空
MsgBox "当前单元格为空,请输入数据后再执行本程序!"
Else '单元格不为空
If IsNumeric(ActiveCell.Value) Then '单元格为数值
If ActiveCell.Value = 0 Then '数据为零
ActiveCell.offset(0,1).Value = "零"
ElseIf ActiveCell.Value > 0 Then '数据为正数
ActiveCell.offset(0,1).Value = "正数"
Else '数据为负数
ActiveCell.offset(0,1).Value = "负数"
End If
Else '数据不为数值,则为文本
ActiveCell.offset(0,1).Validation = "文本"
End If
End If
End Sub
这段代码使用了If语句的嵌套结构,嵌套的层次最多为三层。程序代码的功能在代码后面的注释中都进行了说明,其流程图如图7-8所示。
注意:在块If语句的嵌套中,每一个If语句都需要一个End If语句与之对应,在输入代码时最好采用缩进结构,以便于看清楚嵌套的层次,防止少写End If语句。
7.4 循环程序结构
前面介绍了使用分支结构让VBA程序具有判断能力,从而使程序实现一定的智能化。但是这种分支结构的程序都是从代码的开始处按顺序执行,只是路途跳过一些语句不执行。
在实际需要中,有时还需要反复操作某一个或几个动作。如果将这种操作编写成VBA代码来完成,则表示程序运行到一个位置后,又返回前面的代码来进行操作,这种结构称为循环结构。VBA中提供了多种循环结构控制语句。
7.4.1 Do……Loop循环
用Do循环重复执行一语句块,且重复次数不定。“Do……Loop”语句有4种演变形式,但每种都需要计算条件表达式的值,以决定是否继续执行。在Do循环中可以使用“Exit Do”语句中途退出该循环。
1. Do While……Loop循环
“Do While”语句属于先测试循环条件的“Do……Loop”语句,其语法格式如下:
Do While 逻辑表达式
语句序列1
[Exit Do]
[语句序列2]
Loop
其中Do While和Loop都是关键字,在Do While和Loop之间的语句称为循环体。
当VBA执行这个Do循环时,首先判断逻辑表达式:如果为False(或零),则跳过所有语句,执行Loop的下一条语句:如果为True(或非零),则执行循环体,当执行到Loop语句后,又跳回到Do While语句再次判断条件。在循环体中如果包含有Exit Do语句,当执行到Exit Do语句,马上跳出循环,执行Loop的下一条语句。其流程图如图7-9所示。
这种形式的循环体可能执行零次或多次。只要条件表达式为True或非零,循环就会重复执行。如果逻辑表达式最初就为False,则不会执行循环语句。
2. Do……Loop While循环
“Do……Loop While”语句属于后测试循环条件的“Do……Loop”语句,该结构先执行循环体中的语句,然后再进行条件判断。这种形式的循环体至少执行一次,其语法格式如下:
Do
语句序列1
[Exit Do]
[语句序列2]
Loop While 逻辑表达式
其流程图7-10所示。
3. Do Until……Loop循环
该语句为先测试结束条件的“Do……Loop”语句,其语法形式如下:
Do Until 逻辑表达式
语句序列1
[Exit Do]
[语句序列2]
Loop
这种形式与“Do While……Loop”类似,不同的是当逻辑表达式的值为False时才执行循环体,否则退出循环。这种形式的循环体可能执行零次或多次。
4.Do……Loop Until循环
这是后测试结束条件的“Do……Loop”语句,其语法形式如下:
Do
语句序列1
[Exit Do]
[语句序列2]
Loop Until 逻辑表达式
这种形式与“Do……Loop While”类似,不同的是当逻辑表达式的值为False时才执行循环体,否则退出循环。这种形式的循环体至少能被执行一次。
例如,在要求用户输入密码时,一般都要给用户三次机会,每次的输入过程和判断过程都相同,这时就可以使用循环语句。
Sub 输入密码()
Dim strPassword As String '保存密码
Dim i As Integer '输入密码的次数
Do
strPasswor = InputBox("请输入密码") '输入密码
If strPassword = "wyh" Then '判断密码是否正确
Exit Do '退出循环
Else
MsgBox("请输入正确的密码!")
End If
i = i + 1
Loop While i < 3
If i >= 3 Then '超过正常输入密码次数
MsgBox "未登录用户"
End
Else
MsgBox "欢迎你使用本系统!"
End If
End Sub
程序中使用“Do……Loop While”循环让循环体至少执行一次。程序的流程图如图7-11所示。
在循环体中,首先是显示一个输入框让用户输入密码;接着对用户输入的密码进行判断,如果密码正确,则执行Exit Do语句退出循环,执行Loop While下面的语句,如果密码错误,将显示一个提示信息,并累计错误次数;最后判断是否继续循环。
7.4.2 While……Wend循环
“While……Wend”循环语句的功能与“Do……While”循环相同,是从Basic的早期版本中保留下来的语句,VBA保留它是为了向后兼容,其语法格式如下:
While 逻辑表达式
循环体
……
Wend
如果“逻辑表达式”为True,则所有的“循环体”语句都会执行,一直执行到Wend语句,然后再回到While语句,并再一次检查“逻辑表达式”的值,如果还是为True,则重复执行;如果不为True,则程序会从Wend语句之后的语句继续执行。
7.4.3 For……Next循环
“For……Next”语句以指定次数来重复执行循环体。与Do循环不同,For循环使用一个叫做计数器的变量,每重复一次循环之后,计数器变量的值就会增加或减少。在For循环中可以使用Exit For语句随时退出该循环。For循环的语法格式如下:
For 循环变量=初始值 To 终值 [Step 步长值]
语句序列1
[Exit For]
语句序列2
Next [循环变量]
其中:步长值可正可负。如果步长值为正,则初始值必须小于或等于终值才能执行循环体,否则退出循环;如果步长值为负,则初始值必须大于或等于终值,这样才能执行循环体。如果没能设置Step,则步长值默认为1。“For……Next”循环结构的流程图如图7-12所示。
VBA执行For循环时的过程如下:
步骤1 将初始值赋值给循环变量。
步骤2 判断循环变量是否超过终值,若为真(True),退出循环,执行Next的下一语句。这里的“超过终值”有两种意思:若步长值为负数时,超过就是循环变量的值小于终值;而当步长值为正数时,超过就是循环变量的值大于终值。
步骤3 执行循环体。
步骤4 循环体执行完后到达Next语句时,循环变量累加上步长值。
步骤5 重复步骤2到步骤4。
For循环一般都可计算出循环体的执行次数,计算公式如下:
循环次数=【(终值-初值)/步长值】+1
这里用中括号表示取整。
在事先不知道循环体需要执行多少次时,应该用Do循环;而在知道循环体要执行的次数时,最好使用“For……Next”循环。
例如,要编写代码完成以下工作:在工作表“Sheet2”的前100行中,如果第2列单元格的值为0,则删除所在行。可使用“For……Next”循环语句编写如下代码:
Sub 使用 For 循环删除为0的行()
Dim i As Integer
With Sheets("sheet2")
For i = 1 To 100
If .Cells(i,2).EntireRow.Delete
End If
Next
End With
End Sub
比较两个过程可以看出,使用“For……Next”循环时,不需要开发人员手工编写代码更新循环变量,而使用“Do While……Loop”循环时,必须在循环体中包含更改循环条件的语句,否则循环将一直执行下去,永远退不出来,形成死循环。
7.4.4 循环的嵌套
与分支结构类似,循环结构也可进行嵌套,即将一个循环放置在另一个循环中。VBA允许在同一过程里嵌套多种类型的循环。
在编写嵌套循环程序的代码时一定要注意每个循环语句的配对情况。如图7-13所示,其中(a)是正确的嵌套关系,第一个Next关闭了内层的For循环,而最后一个Loop关闭了外层的Do循环。同样,在嵌套的If语句中,End If语句自动与最靠近的前一个If语句配对。嵌套的Do……Loop结构的工作方式也是一样的,最内圈的Loop语句与最内圈的Do语句匹配。图7-13(b)则是错误的嵌套关系。
第4章中编写的九九乘法表就使用了两个For循环进行嵌套,其代码如下:
Private Sub cmd99_Click()
Dim i As Integer
Dim j As Integer
Dim StrMsg As String
For i = 1 To 9
For j = 1 To 9
strMsg = strMsg & "*" & j & "=" & i * j & ""
Next j
strMsg = strMsg & vbCrLf
Next i
MsgBox strMsg , , "九九乘法表"
End Sub
分析嵌套循环时,可从最内层的循环开始。以上代码最内层循环的语句为:
For j= 1 To 9
strMsg = strMsg & i & "*" & j & "=" & i * j & " "
Next j
这部分代码用来生成一行数据,假设i为1,执行完以上代码后,变量strMsg保存的内容如下:
1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9
将内循环精简为一个命令(如本例中的“输出一行数据”),则九九乘法表的程序变为以下形式:
Private Sub cmd99_Click()
Dim i As Integer
Dim j As Integer
Dim strMsg As String
For i = 1 To 9
输出一行数据
strMsg = strMsg & vbCrLf
Next i
MsgBox strMsg, , "九九乘法表"
End Sub
即可得到一个单循环。该单循环执行9次即可得到9行数据,也就得到了需要的乘法表。
注意:在嵌套结构里的循环结构中使用Exit语句时,退出的只是包含该语句的当前循环结构,而不是整个黄磊结构。
7.4.5 Goto语句
使用Goto语句,可无条件地将程序代码跳转到指定的行去执行。VBA中保留Goto语句是为了保持与早期的Basic版本兼容。Goto语句的语法格式如下:
Goto 行号/标号
注意:Goto只能跑到它所在过程中的行。
要使用Goto语句,首先需用了解VBA中语句的行号和标号。在早期的Basic语言中,每一行程序都有一个行号,行号按从小到大的顺序排列,例如:
Sub 使用Do循环删除为0的行()
10 Dim i As Integer
20 i = 1
30 With Sheets("sheet2")
40 Do While i <= 100
50 If .Cells(i,2) = 0 Then
60 .Cells(i,2).EntireRow.Delete
70 End If
80 i = i + 1
90 Loop
100 End With
End Sub
在VBA中,执行这样的代码也不会出错。为程序添加行号的目的就是方便使用Goto语句跳转到相应的语句去执行。
随着结构化程序设计方法的使用,使用Goto语句跳转的方式已经不常用了,也就不再需要为每行代码添加行号了。
为了使Goto跳转到需要的地方,可在程序中添加标号。标号是以英文字母开头的一个标识符后加上一个冒号构成的。在程序代码中输入的标号始终是靠左对齐的。
例如,以下代码使用Goto语句来进行循环操作,删除单元格为0的行。
Sub 使用Goto语句删除为0的行()
Dim i As Integer
i = 1
linel:
With Sheets("sheet2")
If .Cells(i,2) = 0 Then
.Cells(i,2).EntireRow.Delete
End If
i = i + 1
If i <= 100 Then GoTo linel
End With
End Sub
注意:这里只是演示Goto语句的用法,不建议读者在程序中使用太多的Goto语句,因为使用Goto语句会使程序代码不容易阅读及调试。应尽可能使用结构化控制语句(Do……Loop,For……Next,If……Then……Else和Select Case)。