Folosirea buclelor For... pentru repetări fixe

Buclele For... sunt executate de un număr fix de ori. Buclele For...Next se repetă de numărul de ori ales, iar buclele For Each...Next sunt executate o dată pentru fiecare element dintr-o colecție VBA specificată.

Buclele For...Next

O buclă For...Next repetă o acțiune sau o secvență de acțiuni de un anumit număr de ori. Numărul de repetări este specificat de o variabilă contor (counter variable). Variabila contor poate fi codată în procedură, obținută dintr-o casetă de intrare sau casetă de dialog sau obținută dintr-o valoare generată fie de procedura curentă, fie de o altă procedură.

SINTAXĂ

Sintaxa pentru buclele For...Next este următoarea:

For counter = start To end [Step stepsize]
 [instructiuni]
[Exit For]
 [instructiuni]
Next [counter]

Iată ce se petrece în bucla For...Next (referitor la sintaxă):

  • Când VBA intră în buclă la comanda For, atribuie valoarea start la contor.
  • Execută instrucțiunile din buclă. Când ajunge la instrucțiunea Next, incrementează contorul cu 1 sau cu mărimea stepsize specificată și revine la comanda For.
  • VBA compară variabila contor cu variabila end. Dacă stepsize este pozitiv și contor este mai mare decât end, VBA termină bucla și continuă execuția procedurii cu comanda care se află imediat după comanda Next (care poate fi orice acțiune sau sfârșitul procedurii). Dacă contor este mai mic sau egal cu end, VBA repetă comenzile din buclă, incrementează contor cu 1 sau cu stepsize, apoi revine din nou la comanda For. (Pentru o buclă în care stepsize este negativ, bucla continuă până când contor este mai mare sau egal cu end și se încheie când contor este egal sau mai mic decât end. Altfel zis, când stepsize este negativ, bucla numără înapoi în loc să numere înainte.)
  • Comanda Exit For încheie mai rapid bucla For....

Mai jos sunt prezentate exemple de folosire a comenzii Exit For și a buclei For...Next.

Tabelul următor descrie componentele din sintaxa buclei For...Next. Ca de obicei, parantezele pătrate conțin instrucțiuni opționale și cuvintele scrise înclinat sunt placeholders - elemente din cod care sunt înlocuite de programator.

Buclele simple For...Next

Într-o buclă simplă For...Next, mai întâi trebuie să specificați un nume pentru variabila counter și valorile de început și final pentru ea:

Dim i As Integer For i = 1 to 200

Aici, variabila counter este i, valoarea de pornire este 1, iar valoarea de final este 200. Pentru că VBA incrementează implicit variabila counter cu valoarea 1 la fiecare iterație a buclei, variabila counter din acest exemplu va număra 1, 2, 3, și așa mai departe până la 200. Bucla va fi iterată încă o dată, cu valoarea 201 pentru counter, iar execuția buclei se va încheia și VBA va trece la următoarele comenzi de sub instrucțiunea End a buclei.

Se poate folosi cuvântul cheie Step pentru a specifica o altă valoare de incrementare, care poate fi pozitivă sau negativă – descrierea mai jos.

Numele Tradiţional al variabilei Counter din buclele For...Next

Într-o buclă For...Next, i este variabila clasică de tip integer folosită pentru contor (counter); dacă i este deja folosit, convenția este să se folosească j, k, l, m și n pentru alte variabile contor ulterioare (dacă sunt adăugate bucle imbricate într-o buclă i).

Aceste nume scurte de variabile au fost alese la începuturile programării, când memoria de lucru era mică și numele mai lungi reprezentau o extravaganță semnificativă. În zilele noastre, memoria computerului este mult mai mare, deci utilizarea unor nume lungi de variabile este o practică obișnuită pentru majoritatea variabilelor, dar nu și la contoarele de bucle. Folosirea i ca și contor de bucle este omniprezentă, chiar și în limbaje de programare precum Java și C ++, deci se folosește i.

După cele două declarații anterioare (Dim și For), se specifică toate acțiunile care trebuie efectuate în buclă, urmate de cuvântul Next pentru a încheia bucla:

Application.StatusBar = _
"Va rugam asteptati pana Excel verifica preturile neuniforme: "&i&"..."
Next i

Acest cod afișează (în bara de stare) a aplicației Excel progresul verificării foii de calcul pentru valori improbabile.

Iată un alt exemplu: Trebuie verificat fiecare paragraf din documentele Word primite de la colaboratori pentru vedea că nu există o formatare inadecvată. Folosind o buclă care rulează de la 1 la numărul total de paragrafe din documentul activ, se poate verifica pe rând fiecare paragraf, iar în bara de stare se poate vedea progresul acțiunii. Numărul de paragrafe dintr-un document este stocat în proprietatea Count a colecției Paragraphs din obiectul ActiveDocument:

 Dim i As Integer
For i = 1 To ActiveDocument.Paragraphs.Count 
'VerificareParagrafePentruFormatareInadecvata 
DoEvents
   Application.StatusBar = _
     "Va rugam asteptati pana cand Word verifica formatarea din " _
     & " acest document: Paragraful " & i & " din " _
     & ActiveDocument.Paragraphs.Count & "..."
 Selection.MoveDown Unit:=wdParagraph, _
   Count:=1, Extend:=wdMove
Next i

Acest cod execută procedura VerificareParagrafePentruFormatareInadecvata. Încă nu a fost scrisă procedura, ci doar o linie de comentariu care indică că procedura trebuie apelată din această buclă.

În continuare, se folosește comanda DoEvents. Acest lucru îmbunătățește multitaskingul. Întrerupe bucla pentru a verifica dacă se întâmplă altceva în computer (dacă se tastează ceva, bara de stare în Word este actualizată sau orice altceva). Acest lucru împiedică ca bucla să blocheze microprocesorul computerului.

Apoi bucla continuă să se execute. Mesajul este afișat în bara de stare, indicând numărul de paragraf din numărul total la care lucrează, apoi bucla se deplasează în jos la următorul paragraf. Când VBA ajunge la instrucțiunea Next, aceasta crește contorul i cu valoarea implicită, 1 (pentru că nu este specificată o altă variabilă stepsize în instrucțiunea For) și se întoarce la starea For, unde se compară valoarea lui i cu valoarea din ActiveDocument.Paragraphs.Count. Procedura continuă să facă bucla până când se ajunge la valoarea ActiveDocument.Paragraphs.Count, care este iterația finală a buclei. Aici variabila contorului este utilizată de două ori: mai întâi pentru a urmări iterațiile buclei, dar și ulterior în interiorul buclei pentru a afișa numărul curent al paragrafului:

Paragraful " & i &

În mod similar, se poate utiliza o buclă simplă For...Next pentru a construi rapid structura unei foi de lucru sau a registrului de lucru din Excel. Următoarele comenzi folosesc o buclă For...Next pentru a insera etichetele de la 1:00 la 24:00 în coloana curentă din foaia activă a registrului activ:

Dim i As Integer 
For i = 1 To 24
ActiveCell.FormulaR1C1 = i & ":00"
ActiveCell.Offset(RowOffset:=1, ColumnOffset:=0).Select 
Next i

Aici, comanda ActiveCell.FormulaR1C1 inserează automat valoarea contorului i urmată de două puncte și două zerouri (pentru a crea un format pentru timp).

Comanda

ActiveCell.Offset(RowOffset:=1, ColumnOffset:=0).Select 

selectează celula de pe rândul următor, de pe aceeași coloană. Bucla va fi executată de la i = 1 până la i = 24 și se va opri când valoarea pentru i va fi incrementată la 25. Și aici, variabila contorului este folosită în buclă. Acest lucru este des folosit.

Buclele For...Next cu valori pentru Step

Atunci când incrementarea cu 1 a variabilei pentru contor nu corespunde cerințelor, se poate folosi cuvântul cheie Step pentru a specifica o altă valoare.

De exemplu, comanda următoare incrementează variabila contor cu 20, deci secvența va fi 0, 20, 40, 60, 80, 100:

For i = 0 to 100 Step 20

Se poate și scădea valoarea, folosind o valoare negativă pentru Step:

For i = 1000 to 0 Step -100

Această comandă produce secvența 1000, 900, 800 etc. până la 0.

În loc de numărătoarea inversă „x ramase din y” dată în exemplul din secțiunea precedentă, se poate produce o numărătoare inversă care rulează de la ActiveDocument.Paragraphs.Count până la zero:

Dim i As Integer
For i = ActiveDocument.Paragraphs.Count To 0 Step -1
CheckParagraphForlllegalFormatting 
Application.StatusBar = _
"Va rugam asteptati pana cand Word verifica formatarea din acest document: " & i Selection.MoveDown Unit:=wdParagraph, Count:=1, Extend:=wdMove 
Next i

Folosirea unei casete de dialog pentru a determina bucla FOR...NEXT

Uneori se cunoaște numărul de iterații dintr-o buclă For...Next, astfel încât se poate introduce doar numărul de iterații, de exemplu 100, ca aici:

For i = 0 to 100

Totuși, în alte cazuri, nu se poate ști în prealabil câte iterații de buclă sunt necesare. Aceste informații devin disponibile numai în timpul executării programului (numit timp de execuție - runtime) și nu atunci când este scris codul (numit timp de proiectare - design time).

Adesea, se poate prelua un număr dintr-o altă operație în timpul execuției, cum ar fi proprietatea ActiveDocument.Paragraphs.Count din exemplul precedent.

Pentru a folosi macrocomanda la mai multe documente în viitor, iar numărul de paragrafe din diferite documente este diferit, nu se poate ști când se scrie codul de câte ori ar trebui să se repete bucla. Macrocomanda trebuie să preia informația respectivă în timpul rulării.

Sunt și cazuri când se cere utilizatorului să specifice numărul de repetări ale buclei. Cel mai simplu mod de a face acest lucru este folosind o casetă de intrare, în care utilizatorul va introduce o valoare.

De exemplu, procedura de mai jos conține o procedură simplă, denumită CrearePrezentari, cu o casetă de intrare care solicită utilizatorului să introducă numărul de prezentări care va fi creat. Apoi folosește o buclă For...Next pentru a crea documentele în PowerPoint.

1. Sub CrearePrezentari()
2.  Dim intPrezentari As Integer
3.  Dim i As Integer
4.  intPrezentari = InputBox _
    ("Introduceti numarul de prezentari care va fi creat:", _ 
    "Creare Prezentari")
5.  For i = 1 To intPrezentari
6.  Presentations.Add
7.  Next i
8. End Sub

Iată ce se petrece în procedura CrearePrezentari de mai sus:

  • Linia 2 declară variabila intPrezentari de tip Integer, iar linia 3 declară variabila i de tip Integer.
  • Linia 4 afișează o casetă care cere utilizatorului să introducă numărul de prezentări care va fi creat.
  • Liniile de la 5 până la 7 conțin o buclă For...Next care rulează de la i = 1 până la i = intPrezentari cu incrementarea implicită 1 pe iterație. Fiecare iterație a buclei execută comanda Presentations.Add de pe linia 6, creând o prezentare nouă bazată pe șablonul implicit.

Controlul unei bucle For...Next cu datele introduse de utilizator într-o casetă de dialog

O casetă de intrare returnează o singură valoare. Uneori, este nevoie de mai multe valori din partea utilizatorului. În aceste cazuri, introducerea într-o casetă de dialog conduce la o buclă For...Next. În această secțiune este descrisă o procedură numită Creare_Foldere. Acest exemplu de procedură creează mai multe foldere cu nume previzibile, de exemplu crearea de foldere pentru fiecare capitol din carte.

Presupunând că se va folosi un număr format din patru cifre pentru a identifica un proiect, câte o literă pentru secțiune și apoi un număr format din două cifre pentru a identifica secțiunea, deci folderele vor fi numite 1234s01, 1234s02, 1234s03 etc. Acest lucru poate fi realizat și manual, dar este obositor dacă este nevoie de mai mult de 10 foldere.

În forma sa cea mai simplă, această casetă de dialog ar furniza o casetă text pentru numărul de foldere care trebuie create (deși se poate folosi și o listă derulantă pentru acest lucru sau chiar un control de tip spinner) și o casetă text pentru numărul proiectului. Următoarea ilustrație este un exemplu despre cum ar putea arăta această casetă de dialog.

Se afișează o casetă de dialog folosind metoda Show într-o macrocomandă separată, mai întâi cu instrucțiunea Load, astfel:

Sub CreareFoldere()
Dialogs(wdDialogFileSaveAs).Show 
Load frmCreateFolders 
frmCreateFolders.Show 
End Sub

Comanda Dialogs din cod este utilă și va fi descrisă la final. Urmează buclele.

Caseta de dialog este numită frmCreareFoldere, dar poate fi folosit oricare alt nume valid în VBA. Prima casetă text, care are eticheta Numar Foldere de Creat, are numele txtFoldere; a doua casetă text are numele txtNumarProiect.

Butonul Cancel are instrucțiunea End atașată la evenimentul Click, deci dacă utilizatorul face clic pe buton, VBA iese din procedură:

Private Sub cmdCancel_Click()
  End 
End Sub

Butonul OK din caseta de dialog are atașat următorul cod la evenimentul Click:

1. Private Sub cmdOK_Click()
2. 
3. Dim strMsg As String
4. Dim strFolder As String
5. Dim i As Integer
6. 
7. frmCreareFoldere.Hide
8. Unload frmCreareFoldere
9. strMsg = "Procedura Creare_Foldere a creat  " _
     & "urmatoarele foldere: " & vbCr & vbCr
10.  
11. For i = 1 To txtFoldere.Value
12. strFolder = txtNumarProiect.Value & "p" & Format(i, "0#")
13. MkDir strFolder
14. strMsg = strMsg & " " & strFolder & vbCr
15. Next i
16. 
17. MsgBox strMsg, vbOKOnly + vbInformation, _
     "Creare Foldere"
18. 
19. End Sub

De reținut: Nimeni nu memorează toate variațiile comenzii Format sau toate constantele vb, precum vbCr. Există tone de exemple de cod ca acesta pe Internet și în cărți. Mai mult, Editorul VBA în sine afișează listele de constante și membrii obiectului în timp ce se introduce o linie de cod.

Proprietățile Value ale celor două casete text sunt folosite în buclă. Valoarea din txtFoldere specifică numărul de iterații din buclă. Valoarea txtNumarProiect specifică prima parte a numelui pentru fiecare folder nou creat.

Procedura cmdOK_Click este executată când utilizatorul face clic pe butonul OK din caseta de dialog:

  • Linia 1 declară subrutina cmdOK_Click, iar linia 19 o încheie.
  • Linia 3 declară variabila strMsg de tip String, folosită pentru șirul de caractere care va fi afișat într-un mesaj la finalul procedurii.
  • Linia 4 declară variabila strFolder de tip String, care va conține numele folderului curent care va fi creat la fiecare iterație a buclei.
  • Linia 5 declară variabila i de tip Integer, care va fi contorul buclei For...Next.
  • Linia 7 ascunde frmCreateFolders.
  • Linia 8 descarcă frmCreateFolders din memorie.
  • Linia 9 atribuie textul introductiv în strMsg și se încheie cu două puncte și două vbCr – caractere Enter pentru a începe lista de foldere.
  • Liniile de la 11 până la 15 conțin bucla For...Next care crează folderele. Linia 11 începe bucla de la i = 1 până la i = txtFoldere.Value, valoarea introdusă de utilizator în caseta text numită Numar Foldere de Creat. Linia 12 atribuie variabilei strFolder de tip String proprietatea Value a casetei text txtNumarProiect, litera p, apoi valoarea lui i formatată cu funcția Format pentru a include un zero înainte dacă e o singură cifră (deci va apare ca 01 etc.). Linia 13 folosește comanda MkDir cu strFolder pentru a crea folderul cu acel nume (aceeași comandă ca în MS-DOS). Linia 14 adaugă spații (pentru indentare), conținutul din strFolder, apoi caracterul vbCr la strMsg. Linia 15 sare înapoi la comanda For (linia 11), crescând cu 1 valoarea contorului i. Apoi VBA compară valoarea din contorul i cu valoarea txtFoldere.Value și repetă bucla dacă este nevoie.

Această procedură creează un set de subfoldere noi în folderul curent, fără a da utilizatorului o șansă de a alege locația. În situațiile reale, se preferă ca utilizatorul să poată alege calea la folder. Acest lucru se poate face prin afișarea unei casete de dialog, la fel ca și caseta de dialog Save As folosită de majoritatea aplicațiilor Windows. Aceste căsuțe de dialog încorporate pot fi foarte utile deoarece toată lumea care folosește Windows este familiarizată cu ele și pentru că conțin o anumită funcționalitate. De exemplu, caseta de dialog clasică Windows SaveAs se poate afișa astfel:

Dialogs(wdDialogFileSaveAs).Show

Atunci când utilizatorul închide această casetă de dialog, orice dosar/folder specificat de utilizator devine folderul curent și documentul este salvat automat. Puteți afla mai multe despre cum să utilizați căsuțele de dialog obișnuite pe această pagină web Microsoft:

http://msdn.microsoft.com/en-us/library/bb208857.aspx

Căsuțele de dialog comune există și pot fi foarte utile. Însă, în acest exemplu, o modalitate mai directă de a permite utilizatorului să specifice calea pentru noile directoare ar fi să utilizeze comanda ChDir (schimbare director), astfel:

Dim strDir As String
strDir = InputBox("Tastati calea completa unde vor fi stocate folderele") 
ChDir (strDir)

Buclele For Each...Next

Bucla For Each...Next (care este unică în diferite versiuni ale Visual Basic, inclusiv VBA) seamănă cu bucla For...Next. Bucla funcționează cu colecții. Iterațiile se bazează pe numărul de obiecte dintr-o colecție, cum ar fi colecția Slides dintr-o prezentare sau colecția Documents din documentele Word. Folosind For Each, programatorul nu mai trebuie să știe dinainte numărul de iterații, dar VBA îl va calcula în timpul executării procedurii interogând proprietatea obiectului Count.

De exemplu, să presupunem că trebuie modificat fiecare obiect Slide dintr-o prezentare. În timpul proiectării, la scrierea macrocomenzii, nu se cunoaște câte diapozitive vor fi în colecție. (Dacă nu există, nu se întâmplă nimic.)

SINTAXĂ

Sintaxa pentru comanda For Each...Next este simplă:

For Each obiect In collection 
   [instructiuni]
   [Exit For]
   [instructiuni]
Next [obiect]

VBA începe evaluarea numărului de obiecte din colecția specificată. Apoi, execută instrucțiunile din buclă pentru primul dintre acele obiecte. Când ajunge la Cuvântul cheie Next (Următorul), VBA revine la linia For Each, reevaluează numărul de obiecte și efectuează iterații suplimentare, după caz.

Iată un exemplu: Colecția Documents conține documentele deschise în Word. Așadar, se poate crea o procedură simplă pentru a închide toate documentele deschise, utilizând o buclă For Each...Next, astfel:

Dim Doc As Document 
For Each Doc in Documents
   Doc.Close SaveChanges:=wdSaveChanges
Next

VBA închide pe rând fiecare document deschis, folosind metoda Close. Instrucțiunea folosește constanta wdSaveChanges pentru argumentul SaveChanges pentru a specifica faptul că orice modificare nesalvată a documentului va fi salvată la închiderea documentului. Atâta timp cât există documente deschise în colecția de documente, VBA repetă bucla, astfel încât închide toate documentele deschise, apoi termină procedura.

Acest exemplu oferă o ilustrare simplă a modului în care funcționează o buclă For Each...Next, dar probabil în practică nu se va folosi acest exemplu. În schimb, se poate folosi metoda Close cu colecția Documents (această colecție conține toate documentele deschise) pentru a închide toate documentele deschise. Este o abordare mai simplă. Cu toate acestea, se poate utiliza o buclă For Each...Next pentru a verifica anumite documente pentru anumite caracteristici înainte de închiderea lor.

Folosirea comenzii Exit For

Așa cum s-a prezentat mai sus, în sintaxa pentru instrucțiunile For, se pot utiliza una sau mai multe instrucțiuni Exit For pentru a ieși dintr-o buclă For, dacă este îndeplinită o anumită condiție. Comenzile Exit For sunt opționale și sunt rareori necesare; de fapt, în general se folosesc mai rar. Dacă este neapărat necesară folosirea declarației Exit For într-o procedură, probabil că este ceva în neregulă cu modul în care sunt construite buclele.

Este posibil ca instrucțiunile Exit For să fie utile - de exemplu, pentru a răspunde la o eroare care se întâmplă într-o buclă sau dacă utilizatorul alege să anuleze o procedură.

În acele ocazii, când este nevoie de instrucțiunea Exit For pentru a ieși din buclă din timp, ele sunt folosite în mod normal în condiții simple. De exemplu, în Word, pentru a închide ferestrele deschise până când se ajunge la un anumit document deschis, se poate utiliza o declarație Exit For:

Dim Doc As Document 
For Each Doc in Documents
If Doc.Name = "Document1" Then 
Exit For Doc.Close 
Next Doc

Comanda For Each...Next verifică proprietatea Name a documentului pentru a vedea dacă se numește Document1; dacă da, comanda Exit For face ca VBA să iasă din buclă. Altfel, VBA închide documentul și revine la începutul buclei.

Dacă este nevoie se pot folosi mai multe comenzi Exit For

Se pot utiliza, de asemenea, mai multe declarații Exit For. De exemplu, atunci când este nevoie să se verifice două sau mai multe condiții în timpul acțiunilor efectuate în buclă.