Buclele Do oferă mai multă flexibilitate decât buclele For, prin faptul că se pot testa condițiile și, în consecință, direcționa fluxul procedurii. VBA include mai multe tipuri de bucle Do:
Aceste bucle se pot împărți în două categorii:
Diferența dintre cele două tipuri de bucle din fiecare categorie este că fiecare buclă While se repetă pe sine însăși atâta timp (while) cât condiția este True (până când condiția devine False), iar fiecare buclă Until se repetă până când (until) condiția devine True (atâta timp cât condiția rămâne False).
Acest lucru înseamnă că puteți folosi într-o oarecare măsură doar buclele While sau doar buclele Until - trebuie doar să configurați invers unele dintre condiții. De exemplu, puteți utiliza o buclă Do while...Loop cu condiția x <100 sau o buclă Do Until...Loop cu condiția x = 100 pentru a obține același efect. Altfel spus: bucla While x <100 este echivalentă cu bucla Until x = 100 - atât timp valoarea din condiție este sub 100.
Următoarele secțiuni descriu toate tipurile de bucle Do pentru a înțelege când trebuie folosite.
Buclele Do While...Loop
Într-o buclă Do While...Loop, specificați o condiție care trebuie să rămână True pentru acțiunile (comenzile) din interiorul buclei care urmează să fie executată. Dacă condiția nu este adevărată, acțiunile nu sunt executate și bucla se termină. Când o buclă se termină, se execută codul de sub blocul de buclă.
De exemplu, la căutarea într-un document a unei instanțe a unui anumit cuvânt sau expresie și acționarea unor comenzi după ce găsirea instanței. Imaginea următoare prezintă o buclă Do while...Loop, care testează o condiție înainte de a realiza acțiunile din buclă.
SINTAXĂ
Sintaxa pentru bucla Do While...Loop este simplă:
Do While condition
[instructiuni]
[Exit Do]
[instructiuni]
Loop
Atâta timp cât condition este îndeplinită (Fă acest lucru atâta timp cât condiția rămâne adevărată), instrucțiunile din buclă sunt executate. Cuvântul cheie Loop întoarce execuția la linia Fă (Do), care este reevaluată. Dacă condition este încă adevărată, bucla continuă - se iterează din nou.
Însă dacă condition este falsă, execuția sare la codul de sub blocul de buclă, începând cu instrucțiunea de pe linia de după cuvântul cheie Loop.
Puteți utiliza una sau mai multe instrucțiuni Exit Do opționale dacă doriți să ieșiți din buclă fără să așteptați până când condition devine falsă.
De exemplu pentru a construi un glosar dintr-un document Word lung, care evidențiază termenii principali prin scriere înclinată. Acești termeni se găsesc în textul corpului, precum și în listele cu buline sau numerotate. Cu toate acestea, doriți să evitați să alegeți termeni italici folosiți în alte elemente ale documentului, cum ar fi titluri (heading) sau captions. În această situație, textul corpului scris cu fontul Times New Roman, iar subtitrările și titlurile sunt scrise cu alte fonturi.
Ați putea comanda Word să caute text Times New Roman cu atributul italic. Dacă Word a găsit instanțe ale textului, ar lua măsurile adecvate, cum ar fi selectarea propoziției care conține termenul, împreună cu următoarea propoziție (sau restul alineatului) și copierea acesteia la sfârșitul unui alt document. Apoi va continua căutarea, efectuând bucla până nu va mai găsi cazuri de text italic Times New Roman.
Exemplul de mai jos prezintă modul în care ar putea fi construită o astfel de procedură cu o structură Do while...Loop. Această listă include o serie de comenzi despre care nu ați aflat încă, dar ar trebui să vedeți cum funcționează bucla acestui cod.
1. Sub GenerareGlosar()
2.
3. Dim strSursa As String
4. Dim strDestinatie As String
5. Dim strNumeGlosar As String
6.
7. strSursa = ActiveWindow.Caption
8. strNumeGlosar = InputBox _
("Introduceti numele pentru documentul glosar.", _ "Creare Glosar")
9. If strNumeGlosar = "" Then End
10.
11. Documents.Add
12. ActiveDocument.SaveAs FileName:=strNumeGlosar, _
FileFormat:=wdFormatDocument
13. strDestinatie = ActiveWindow.Caption
14. Windows(strSursa).Activate
15.
16. Selection.HomeKey Unit:=wdStory
17. Selection.Find.ClearFormatting
18. Selection.Find.Font.Italic = True
19. Selection.Find.Font.Name = "Times New Roman"
20. Selection.Find.Text = ""
21. Selection.Find.Execute
22.
23. Do While Selection.Find.Found
24. Selection.Copy
25. Selection.MoveRight Unit:=wdCharacter, _
Count:=1, Extend:=wdMove
26. Windows(strDestinatie).Activate
27. Selection.EndKey Unit:=wdStory
28. Selection.Paste
29. Selection.TypeParagraph
30. Windows(strSursa).Activate
31. Selection.Find.Execute
32. Loop
33.
34. Windows(strDestinatie).Activate
35. ActiveDocument.Save
36. ActiveDocument.Close
37.
38. End Sub
Procedura GenerareGlosar de mai sus copie elementele scrise înclinat (italic) cu fontul Times New Roman din documentul curent și le inserează într-un document nou pe care îl crează și salvează. Iată ce se petrece:
Bucle Do...Loop While
Un bloc Do...Loop While este similar cu Do While...Loop, cu excepția faptului că la bucla Do...Loop While, instrucțiunile din buclă sunt executate cel puțin o dată.
Chiar dacă condiția este True sau False, bucla este executată cel puțin o dată deoarece condiția este testată abia la finalul blocului buclei.
Dacă condiția este True, bucla continuă să ruleze până când condiția devine False. Figura urm[toare arată o buclă Do...Loop While, în care acțiunile din buclă rulează o dată înainte de a testa condiția.
Blocul Do While...Loop descris mai sus are sens, dar acest bloc Do...Loop While pare ciudat. Cum se pot executa comenzile din bloc înainte de a verifica condiția?
Totuși, buclele Do...Loop While sunt foarte utile, în unele situații diferite de cele în care se folosesc buclele Do While...Loop.
Luați în considerare exemplul de loterie, în care executați acțiunea înainte de a verifica starea care controlează bucla. Mai întâi cumpărați un bilet la loterie, apoi verificați dacă ați câștigat. Dacă nu ați câștigat sau ați câștigat doar o sumă mică, vă bucurați și cumpărați mai multe bilete pentru următoarea loterie. (De fapt, aceasta este în mod logic o buclă Do...Loop Until, mai degrabă decât o buclă Do...Loop While deoarece continuă bucla atâta timp cât condiția este False; atunci când câștigați o cantitate suficient de mare, condiția devine True.)
De asemenea, în programare nu este ceva neobișnuit să întreprindeți o acțiune și apoi să verificați dacă trebuie să o repetați. De exemplu, poate doriți să aplicați o formatare specială la paragraful curent și apoi verificați dacă alte paragrafe au același tratament.
SINTAXA
Sintaxa pentru bucla Do...Loop While este următoarea:
Do
[instructiuni]
[Exit Do]
[instructiuni]
Loop While condition
VBA efectuează instrucțiunile incluse în buclă, după care linia Loop while evaluează starea. Dacă este True, VBA returnează execuția pe linia Do și bucla continuă să se execute; dacă este False, execuția continuă cu linia de după linia Loop while.
Ca exemplu de buclă Do...Loop While, luați în considerare acest verificator de parole pe care l-ați putea folosi pentru a împiedica pe cineva să execute o macrocomandă fără a furniza parola corectă:
Sub pass()
Dim ParolaCorecta As Variant
Dim varParola As Variant
ParolaCorecta = "corinth"
Do
varParola = InputBox _
("Introduceti parola pentru a porni procedura:", _
"Verificare parola 1.0")
Loop While varParola <> ParolaCorecta
End Sub
Aici, bucla Do...Loop While afișează mai întâi o casetă de intrare pentru ca utilizatorul să introducă parola. Linia Loop While compară valoarea din caseta de intrare, stocată în varParola, cu parola corectă (aici, ParolaCorecta). Dacă cele două nu sunt egale (varParola <> ParolaCorecta), bucla continuă, afișând din nou caseta de intrare.
Această buclă este doar un exemplu – nu se folosește așa cum este în viața reală. Iată de ce: alegerea butonului Cancel într-o casetă de intrare determină întoarcerea unui șir gol, care, de asemenea, nu se potrivește cu parola corectă, determinând rularea buclei. Securitatea este perfectă; problema este că singura cale de a încheia bucla este ca utilizatorii să furnizeze parola corectă. Dacă nu pot face acest lucru, vor vedea din nou caseta de introducere. Nu există nicio cale de ieșire din buclă. Aceasta se numește o buclă nesfârșită (endless loop) și este o programare foarte proastă. Utilizatorul poate fi prins fără speranță într-o buclă care se repetă la nesfârșit. Astfel de capcane buclă sunt, de asemenea, numite bucle infinite sau nesfârșite.
Pentru a ieși dintr-o astfel de buclă, se apasă combinația de taste Ctrl+Break.
În schimb, ar trebui să creați o procedură mai ușoară de verificare a parolei. Puteți specifica introducerea de maxim 3 ori a parolei, după care procedura să se încheie. Sau puteți utiliza pur și simplu o instrucțiune End pentru a încheia procedura dacă utilizatorul a introdus un șir blank, astfel:
Do
varParola = InputBox _
("Introduceti parola pentru a porni procedura:", _
"Verificare parola 1.0")
If varParola = "" Then End
Loop While varParola <> "ParolaCorecta"
Buclele Do Until...Loop
O buclă Do Until...Loop seamănă cu o buclă Do While...Loop. Diferența este modul în care funcționează condiția. Într-o buclă Do Until...Loop, bucla rulează până când condiția este False și se oprește atunci când condiția devine True. Deci este inversul modului în care funcționează bucla Do While...Loop.
Figura următoare arată o buclă Do Until...Loop.
Do UNTIL...LOOP BLOCHEAZĂ EXECUȚIA ATÂTA TIMP CÂT CONDIȚIA ESTE FALSE
Rețineți că buclele Do Until...Loop sunt utile dacă preferați să lucrați cu o condiție care este True și să o mențineți în bucle până când starea devine False. În caz contrar, puteți obține aceleași efecte folosind buclele Do While...Loop și inversând starea. Cu alte cuvinte, aceste două abordări ale buclelor funcționează la fel; dvs. alegeți cum doriți să gestionați starea. Este diferența dintre „măturați pridvorul până când este curat” sau „măturați pridvorul atâta timp cât este încă murdar”. Aceeași idee este exprimată diferit.
SINTAXĂ
Sintaxa pentru buclele Do Until...Loop este următoarea:
Do Until condition
instructiuni
[Exit Do]
[instructiuni]
Loop
Când VBA intră în buclă, verifică condition. Dacă aceasta este False, VBA execută declarațiile din buclă, întâlnește cuvântul cheie Loop și se întoarce la începutul buclei, reevaluând condiția. Dacă aceasta este True, VBA încheie bucla și continuă execuția cu instrucțiunea de după linia Loop.
De exemplu, iată din nou exemplul de loterie, dar care acum folosește o buclă Do...Until.
1. Sub Loterie_1()
2. Dim intWin As Integer
3. Do Until intWin > 2000
4. intWin = Rnd * 2100
5. MsgBox intWin, , "Loterie"
6. Loop
7. End Sub
Iată cum funcționează procedura:
Procedura următoare arată un exemplu mai util a buclei Do Until...Loop loop din Word.
1. Sub FindNextHeading()
2. Do Until Left(Selection.Paragraphs(1).Style, 7) = "Heading"
3. Selection.MoveDown Unit:=wdParagraph, _
Count:=1, Extend:=wdMove
4. Loop
5. End Sub
Procedura mută punctul de inserție la următorul antet (heading) din documentul activ în Word. Iată cum funcționează:
Buclele Do...Loop Until
Bucla Do...Loop Until este similară cu structura Do Until...Loop cu excepția faptului că în bucla Do...Loop Until, instrucțiunile conținute în blocul din buclă , chiar dacă condiția este True sau False. Dacă condiția este False, bucla continuă să ruleze până când condiția devine True. Figura următoare afișează o buclă Do...Loop Until.
SINTAXĂ
Sintaxa pentru buclele Do...Loop Until este:
Do
[instructiuni]
[Exit Do]
[instructiuni]
Loop Until condition
VBA intră în buclă la linia Do și execută instrucțiunile din buclă. Atunci când ajunge la linia Loop Until, verifică condition. Dacă condition este False, VBA revine la linia Do și execută din nou instrucțiunile. Dacă condition este True, VBA termină bucla și continuă execuția de la linia de după linia Loop Until.
Ca exemplu, se poate afișa repetat o casetă de introducere date care adaugă foi de lucru în registrul de lucru până când utilizatorul face clic pe butonul Cancel sau nu scrie nimic în text box. Se poate folosi codul de mai jos.
1. Sub Creare_Foi_De_Lucru()
2. Dim strFoaieNoua As String
3. Do
4. strFoaieNoua = InputBox _
("Introduceti numele noii foi de lucru " _
& "(maxim 31 caractere):", "Adaugare foi de lucru")
5. If strFoaieNoua <> "" Then
6. ActiveWorkbook.Worksheets.Add
7. ActiveSheet.Name = strFoaieNoua
8. End If
9. Loop Until strFoaieNoua = ""
10. End Sub
Iată ce se petrece în procedura Creare_Foi_De_Lucru:
Folosirea instrucțiunii Exit Do
Ca și instrucțiunea Exit For din bucla For..., se poate folosi o instrucțiune Exit Do pentru a ieși din bucla Do fără a mai executa instrucțiunile de sub linia Exit. Instrucțiunea Exit este opțională și se folosește rar dacă buclele sunt proiectate corespunzător.
Instrucțiunea Exit Do se folosește împreună cu propria condiție. Exemplul din procedura următoare face loteria mai interesantă prin adăugarea unei condiții If cu instrucțiunea Exit Do pentru a avea efect dacă câștigul este mai mic decât $500.
1. Sub Loterie_2()
2. Dim intWin As Integer
3. Do Until intWin > 2000
4. intWin = Rnd * 2100
5. If intWin < 500 Then
MsgBox "Ghinion. Ai fost descalificat.", vbOKOnly + vbCritical, "Loterie"
6. Exit Do
7. End If
8. MsgBox intWin, , "Loterie"
9. Loop
10. End Sub
Procedura de mai sus funcționează în același mod ca și exemplul Loterie_1, cu excepția faptului că linia 5 introduce o nouă condiție If. Dacă variabila intWin este mai mică decât 500, rulează instrucțiunile de pe liniile 6 și 7. Linia 6 afișează o casetă de mesaj care anunță că jucătorul a fost descalificat din loterie, iar linia 7 iese din bucla Do.
Instrucțiunea Exit Do este nerecomandată?
Unii programatori iau în considerare utilizarea unei instrucțiuni Exit Do pentru a ieși dintr-o buclă Do ca și tactică de ultimă soluție sau cel puțin ca programare stângace. Alții nu sunt de acord. Mulți cred că este întotdeauna acceptabil să utilizeze o declarație Exit Do pentru a răspunde la o eroare sau la utilizator, făcând clic pe butonul Anulare.
VBA execută instrucțiuni Exit Do fără nicio problemă, deci comanda este acolo dacă doriți să o utilizați. Cu toate acestea, puteți rescrie adesea codul pentru a evita utilizarea unei instrucțiuni Exit Do.
De exemplu, o condiție pe care o verificați în mijlocul buclei pentru a decide dacă ieșiți din buclă poate fi adesea încorporată în condiția principală a buclei utilizând un operator precum And, Or sau Not, așa cum se arată în procedura următoare, în care se evită comanda Exit Do:
1. Sub Loterie_3()
2.
3. Dim intWin As Integer
4.
5. Do
6. intWin = Rnd * 2100
7. MsgBox intWin, , "Loterie"
8. Loop Until intWin > 2000 Or intWin < 500
9.
10.
11. If intWin < 500 Then
12. MsgBox "Ghinion. Ai fost descalificat
vbOKOnly + vbCritical, "Loterie"
13.
14. End If
15.
16. End Sub
Procedura Loterie_3 este o revizuire a procedurii Loterie_2. Ea arată cum se folosește operatorul Or pentru a specifica două condiții pentru ca bucla să fie iterată. Astfel, se poate omite cu totul comanda Exit Do.
Instrucțiunea de pe linia 8 din Loterie_3, spune că bucla poate să se termine dacă variabila este mai mare decât 2000 sau mai mică decât 500. Astfel se poate înțelege mai clar ce face bucla.
Mai trebuie făcute două modificări. Prima modificare: se mută condiția test din partea de sus a buclei în partea de jos. Comanda Do Until din Loterie_2 trebuie modificată la comanda Loop Until din Loterie_3. Dacă se lasă condiția test în partea de sus a buclei, condiția va opri întotdeauna executarea buclei. Aceasta deoarece variabila intWin va păstra mereu valoarea zero la prima executare a buclei. Deci, se mută condiția test în partea de jos a buclei, pentru a permite ca variabilei să i se atribuie o valoare pe linia 6.
Modificarea finală este mutarea blocului If...Then în partea de jos a procedurii.
Acest cod simplu poate fi rescris folosind un operator. Dar dacă codul este complex și lung, nu se recomandă folosirea de operatori, pentru că instrucțiunea Exit Do este suficientă.