在使用Is關(guān)鍵字進(jìn)行條件判斷時(shí),條件的先后順序很重要。如本例中,若將Is<100000寫在第一個(gè)條件位置,程序運(yùn)行將得不到正確的結(jié)果。
在一個(gè)分支結(jié)構(gòu)語(yǔ)句中還可以包含另一個(gè)分支結(jié)構(gòu)語(yǔ)句,這稱為嵌套。例如,以下程序用于判斷當(dāng)前單元格中保存值的類型:
MsgBox "當(dāng)前單元格為空,請(qǐng)輸入數(shù)據(jù)后再執(zhí)行本程序?。ⅰ?/div>
Else '單元格不為空
If IsNumeric(ActiveCell.Value) Then '單元格為數(shù)值
If ActiveCell.Value?。健? Then '數(shù)據(jù)為零
ActiveCell.offset(0,1).Value = "零"
ElseIf ActiveCell.Value?。尽? Then '數(shù)據(jù)為正數(shù)
ActiveCell.offset(0,1).Value = "正數(shù)"
Else '數(shù)據(jù)為負(fù)數(shù)
ActiveCell.offset(0,1).Value = "負(fù)數(shù)"
End If
Else '數(shù)據(jù)不為數(shù)值,則為文本
ActiveCell.offset(0,1).Validation = "文本"
End If
End If
End Sub
這段代碼使用了If語(yǔ)句的嵌套結(jié)構(gòu),嵌套的層次最多為三層。程序代碼的功能在代碼后面的注釋中都進(jìn)行了說(shuō)明,其流程圖如圖7-8所示。
注意:在塊If語(yǔ)句的嵌套中,每一個(gè)If語(yǔ)句都需要一個(gè)End If語(yǔ)句與之對(duì)應(yīng),在輸入代碼時(shí)最好采用縮進(jìn)結(jié)構(gòu),以便于看清楚嵌套的層次,防止少寫End If語(yǔ)句。
7.4 循環(huán)程序結(jié)構(gòu)
前面介紹了使用分支結(jié)構(gòu)讓VBA程序具有判斷能力,從而使程序?qū)崿F(xiàn)一定的智能化。但是這種分支結(jié)構(gòu)的程序都是從代碼的開始處按順序執(zhí)行,只是路途跳過(guò)一些語(yǔ)句不執(zhí)行。
在實(shí)際需要中,有時(shí)還需要反復(fù)操作某一個(gè)或幾個(gè)動(dòng)作。如果將這種操作編寫成VBA代碼來(lái)完成,則表示程序運(yùn)行到一個(gè)位置后,又返回前面的代碼來(lái)進(jìn)行操作,這種結(jié)構(gòu)稱為循環(huán)結(jié)構(gòu)。VBA中提供了多種循環(huán)結(jié)構(gòu)控制語(yǔ)句。
7.4.1 Do……Loop循環(huán)
用Do循環(huán)重復(fù)執(zhí)行一語(yǔ)句塊,且重復(fù)次數(shù)不定。“Do……Loop”語(yǔ)句有4種演變形式,但每種都需要計(jì)算條件表達(dá)式的值,以決定是否繼續(xù)執(zhí)行。在Do循環(huán)中可以使用“Exit Do”語(yǔ)句中途退出該循環(huán)。
1. Do While……Loop循環(huán)
“Do While”語(yǔ)句屬于先測(cè)試循環(huán)條件的“Do……Loop”語(yǔ)句,其語(yǔ)法格式如下:
Do While 邏輯表達(dá)式
語(yǔ)句序列1
[Exit Do]
?。壅Z(yǔ)句序列2]
Loop
其中Do While和Loop都是關(guān)鍵字,在Do While和Loop之間的語(yǔ)句稱為循環(huán)體。
當(dāng)VBA執(zhí)行這個(gè)Do循環(huán)時(shí),首先判斷邏輯表達(dá)式:如果為False(或零),則跳過(guò)所有語(yǔ)句,執(zhí)行Loop的下一條語(yǔ)句:如果為True(或非零),則執(zhí)行循環(huán)體,當(dāng)執(zhí)行到Loop語(yǔ)句后,又跳回到Do While語(yǔ)句再次判斷條件。在循環(huán)體中如果包含有Exit Do語(yǔ)句,當(dāng)執(zhí)行到Exit Do語(yǔ)句,馬上跳出循環(huán),執(zhí)行Loop的下一條語(yǔ)句。其流程圖如圖7-9所示。
這種形式的循環(huán)體可能執(zhí)行零次或多次。只要條件表達(dá)式為True或非零,循環(huán)就會(huì)重復(fù)執(zhí)行。如果邏輯表達(dá)式最初就為False,則不會(huì)執(zhí)行循環(huán)語(yǔ)句。
2. Do……Loop While循環(huán)
“Do……Loop While”語(yǔ)句屬于后測(cè)試循環(huán)條件的“Do……Loop”語(yǔ)句,該結(jié)構(gòu)先執(zhí)行循環(huán)體中的語(yǔ)句,然后再進(jìn)行條件判斷。這種形式的循環(huán)體至少執(zhí)行一次,其語(yǔ)法格式如下:
Do
語(yǔ)句序列1
?。跡xit Do]
?。壅Z(yǔ)句序列2]
Loop While 邏輯表達(dá)式
其流程圖7-10所示。
3. Do Until……Loop循環(huán)
該語(yǔ)句為先測(cè)試結(jié)束條件的“Do……Loop”語(yǔ)句,其語(yǔ)法形式如下:
Do Until 邏輯表達(dá)式
語(yǔ)句序列1
[Exit Do]
?。壅Z(yǔ)句序列2]
Loop
這種形式與“Do While……Loop”類似,不同的是當(dāng)邏輯表達(dá)式的值為False時(shí)才執(zhí)行循環(huán)體,否則退出循環(huán)。這種形式的循環(huán)體可能執(zhí)行零次或多次。
4.Do……Loop Until循環(huán)
這是后測(cè)試結(jié)束條件的“Do……Loop”語(yǔ)句,其語(yǔ)法形式如下:
Do
語(yǔ)句序列1
?。跡xit Do]
?。壅Z(yǔ)句序列2]
Loop Until 邏輯表達(dá)式
這種形式與“Do……Loop While”類似,不同的是當(dāng)邏輯表達(dá)式的值為False時(shí)才執(zhí)行循環(huán)體,否則退出循環(huán)。這種形式的循環(huán)體至少能被執(zhí)行一次。
例如,在要求用戶輸入密碼時(shí),一般都要給用戶三次機(jī)會(huì),每次的輸入過(guò)程和判斷過(guò)程都相同,這時(shí)就可以使用循環(huán)語(yǔ)句。
Sub 輸入密碼()
Dim strPassword As String '保存密碼
Dim i As Integer '輸入密碼的次數(shù)
Do
strPasswor = InputBox("請(qǐng)輸入密碼") '輸入密碼
If strPassword = "wyh" Then '判斷密碼是否正確
Exit Do '退出循環(huán)
Else
MsgBox("請(qǐng)輸入正確的密碼!")
End If
i = i + 1
Loop While i < 3
If i >= 3 Then '超過(guò)正常輸入密碼次數(shù)
MsgBox "未登錄用戶"
End
Else
MsgBox "歡迎你使用本系統(tǒng)!"
End If
End Sub
程序中使用“Do……Loop While”循環(huán)讓循環(huán)體至少執(zhí)行一次。程序的流程圖如圖7-11所示。
在循環(huán)體中,首先是顯示一個(gè)輸入框讓用戶輸入密碼;接著對(duì)用戶輸入的密碼進(jìn)行判斷,如果密碼正確,則執(zhí)行Exit Do語(yǔ)句退出循環(huán),執(zhí)行Loop While下面的語(yǔ)句,如果密碼錯(cuò)誤,將顯示一個(gè)提示信息,并累計(jì)錯(cuò)誤次數(shù);最后判斷是否繼續(xù)循環(huán)。
7.4.2 While……Wend循環(huán)
“While……Wend”循環(huán)語(yǔ)句的功能與“Do……While”循環(huán)相同,是從Basic的早期版本中保留下來(lái)的語(yǔ)句,VBA保留它是為了向后兼容,其語(yǔ)法格式如下:
While 邏輯表達(dá)式
循環(huán)體
……
Wend
如果“邏輯表達(dá)式”為True,則所有的“循環(huán)體”語(yǔ)句都會(huì)執(zhí)行,一直執(zhí)行到Wend語(yǔ)句,然后再回到While語(yǔ)句,并再一次檢查“邏輯表達(dá)式”的值,如果還是為True,則重復(fù)執(zhí)行;如果不為True,則程序會(huì)從Wend語(yǔ)句之后的語(yǔ)句繼續(xù)執(zhí)行。
7.4.3 For……Next循環(huán)
“For……Next”語(yǔ)句以指定次數(shù)來(lái)重復(fù)執(zhí)行循環(huán)體。與Do循環(huán)不同,F(xiàn)or循環(huán)使用一個(gè)叫做計(jì)數(shù)器的變量,每重復(fù)一次循環(huán)之后,計(jì)數(shù)器變量的值就會(huì)增加或減少。在For循環(huán)中可以使用Exit For語(yǔ)句隨時(shí)退出該循環(huán)。For循環(huán)的語(yǔ)法格式如下:
For 循環(huán)變量=初始值 To 終值 [Step 步長(zhǎng)值]
語(yǔ)句序列1
?。跡xit For]
語(yǔ)句序列2
Next?。垩h(huán)變量]
其中:步長(zhǎng)值可正可負(fù)。如果步長(zhǎng)值為正,則初始值必須小于或等于終值才能執(zhí)行循環(huán)體,否則退出循環(huán);如果步長(zhǎng)值為負(fù),則初始值必須大于或等于終值,這樣才能執(zhí)行循環(huán)體。如果沒(méi)能設(shè)置Step,則步長(zhǎng)值默認(rèn)為1。“For……Next”循環(huán)結(jié)構(gòu)的流程圖如圖7-12所示。
?。郑拢翀?zhí)行For循環(huán)時(shí)的過(guò)程如下:
步驟1 將初始值賦值給循環(huán)變量。
步驟2 判斷循環(huán)變量是否超過(guò)終值,若為真(True),退出循環(huán),執(zhí)行Next的下一語(yǔ)句。這里的“超過(guò)終值”有兩種意思:若步長(zhǎng)值為負(fù)數(shù)時(shí),超過(guò)就是循環(huán)變量的值小于終值;而當(dāng)步長(zhǎng)值為正數(shù)時(shí),超過(guò)就是循環(huán)變量的值大于終值。
步驟3 執(zhí)行循環(huán)體。
步驟4 循環(huán)體執(zhí)行完后到達(dá)Next語(yǔ)句時(shí),循環(huán)變量累加上步長(zhǎng)值。
步驟5 重復(fù)步驟2到步驟4。
For循環(huán)一般都可計(jì)算出循環(huán)體的執(zhí)行次數(shù),計(jì)算公式如下:
循環(huán)次數(shù)=【(終值-初值)/步長(zhǎng)值】+1
這里用中括號(hào)表示取整。
在事先不知道循環(huán)體需要執(zhí)行多少次時(shí),應(yīng)該用Do循環(huán);而在知道循環(huán)體要執(zhí)行的次數(shù)時(shí),最好使用“For……Next”循環(huán)。
例如,要編寫代碼完成以下工作:在工作表“Sheet2”的前100行中,如果第2列單元格的值為0,則刪除所在行。可使用“For……Next”循環(huán)語(yǔ)句編寫如下代碼:
Sub 使用 For 循環(huán)刪除為0的行()
Dim?。椤s Integer
With Sheets("sheet2")
For i = 1 To 100
If .Cells(i,2).EntireRow.Delete
End If
Next
End With
End Sub
比較兩個(gè)過(guò)程可以看出,使用“For……Next”循環(huán)時(shí),不需要開發(fā)人員手工編寫代碼更新循環(huán)變量,而使用“Do While……Loop”循環(huán)時(shí),必須在循環(huán)體中包含更改循環(huán)條件的語(yǔ)句,否則循環(huán)將一直執(zhí)行下去,永遠(yuǎn)退不出來(lái),形成死循環(huán)。
7.4.4 循環(huán)的嵌套
與分支結(jié)構(gòu)類似,循環(huán)結(jié)構(gòu)也可進(jìn)行嵌套,即將一個(gè)循環(huán)放置在另一個(gè)循環(huán)中。VBA允許在同一過(guò)程里嵌套多種類型的循環(huán)。
在編寫嵌套循環(huán)程序的代碼時(shí)一定要注意每個(gè)循環(huán)語(yǔ)句的配對(duì)情況。如圖7-13所示,其中(a)是正確的嵌套關(guān)系,第一個(gè)Next關(guān)閉了內(nèi)層的For循環(huán),而最后一個(gè)Loop關(guān)閉了外層的Do循環(huán)。同樣,在嵌套的If語(yǔ)句中,End If語(yǔ)句自動(dòng)與最靠近的前一個(gè)If語(yǔ)句配對(duì)。嵌套的Do……Loop結(jié)構(gòu)的工作方式也是一樣的,最內(nèi)圈的Loop語(yǔ)句與最內(nèi)圈的Do語(yǔ)句匹配。圖7-13(b)則是錯(cuò)誤的嵌套關(guān)系。
第4章中編寫的九九乘法表就使用了兩個(gè)For循環(huán)進(jìn)行嵌套,其代碼如下:
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
分析嵌套循環(huán)時(shí),可從最內(nèi)層的循環(huán)開始。以上代碼最內(nèi)層循環(huán)的語(yǔ)句為:
For j= 1 To?。?/div>
strMsg = strMsg & i & "*" & j & "=" & i * j & " "
Next j
這部分代碼用來(lái)生成一行數(shù)據(jù),假設(shè)i為1,執(zhí)行完以上代碼后,變量strMsg保存的內(nèi)容如下:
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
將內(nèi)循環(huán)精簡(jiǎn)為一個(gè)命令(如本例中的“輸出一行數(shù)據(jù)”),則九九乘法表的程序變?yōu)橐韵滦问剑?/div>
Private Sub cmd99_Click()
Dim i As Integer
Dim j As Integer
Dim strMsg As String
For i = 1 To 9
輸出一行數(shù)據(jù)
strMsg = strMsg & vbCrLf
Next i
MsgBox strMsg, , "九九乘法表"
End Sub
即可得到一個(gè)單循環(huán)。該單循環(huán)執(zhí)行9次即可得到9行數(shù)據(jù),也就得到了需要的乘法表。
注意:在嵌套結(jié)構(gòu)里的循環(huán)結(jié)構(gòu)中使用Exit語(yǔ)句時(shí),退出的只是包含該語(yǔ)句的當(dāng)前循環(huán)結(jié)構(gòu),而不是整個(gè)黃磊結(jié)構(gòu)。
7.4.5 Goto語(yǔ)句
使用Goto語(yǔ)句,可無(wú)條件地將程序代碼跳轉(zhuǎn)到指定的行去執(zhí)行。VBA中保留Goto語(yǔ)句是為了保持與早期的Basic版本兼容。Goto語(yǔ)句的語(yǔ)法格式如下:
Goto 行號(hào)/標(biāo)號(hào)
注意:Goto只能跑到它所在過(guò)程中的行。
要使用Goto語(yǔ)句,首先需用了解VBA中語(yǔ)句的行號(hào)和標(biāo)號(hào)。在早期的Basic語(yǔ)言中,每一行程序都有一個(gè)行號(hào),行號(hào)按從小到大的順序排列,例如:
Sub 使用Do循環(huán)刪除為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中,執(zhí)行這樣的代碼也不會(huì)出錯(cuò)。為程序添加行號(hào)的目的就是方便使用Goto語(yǔ)句跳轉(zhuǎn)到相應(yīng)的語(yǔ)句去執(zhí)行。
隨著結(jié)構(gòu)化程序設(shè)計(jì)方法的使用,使用Goto語(yǔ)句跳轉(zhuǎn)的方式已經(jīng)不常用了,也就不再需要為每行代碼添加行號(hào)了。
為了使Goto跳轉(zhuǎn)到需要的地方,可在程序中添加標(biāo)號(hào)。標(biāo)號(hào)是以英文字母開頭的一個(gè)標(biāo)識(shí)符后加上一個(gè)冒號(hào)構(gòu)成的。在程序代碼中輸入的標(biāo)號(hào)始終是靠左對(duì)齊的。
例如,以下代碼使用Goto語(yǔ)句來(lái)進(jìn)行循環(huán)操作,刪除單元格為0的行。
Sub 使用Goto語(yǔ)句刪除為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語(yǔ)句的用法,不建議讀者在程序中使用太多的Goto語(yǔ)句,因?yàn)槭褂肎oto語(yǔ)句會(huì)使程序代碼不容易閱讀及調(diào)試。應(yīng)盡可能使用結(jié)構(gòu)化控制語(yǔ)句(Do……Loop,F(xiàn)or……Next,If……Then……Else和Select Case)。