Crearea unui cod modular

Codul care a fost creat până aici funcționează, dar în unele cazuri nu a fost destul de concis, organizat sau elegant. Următoarele secțiuni descriu cum poate fi îmbunătățit codul.

Ce este eleganța în cod?

Eleganța în programarea pe computer nu înseamnă doar realizarea de cod fără greșeli, bine organizat și proiectat corect pentru interfața utilizatorului, ci și că acel cod nu conține ceva care nu este necesar și a fost redus la minimum necesar pentru a obține efectul dorit.

Ce este codul modular?

Codul modular este codul compus din diferite proceduri care pot fi folosite combinat. Numele nu vine de la faptul că acel cod VBA ar fi stocat în module.

De exemplu, să presupunem că lucrați în Word. Puteți adopta o abordare monolitică și puteți crea o singură macrocomandă gigant care face o mulțime de lucruri: creează un document bazat pe alegerea șablonului de către utilizator, introduce text și formate, îl salvează într-un anumit folder sub un nume ales de utilizator, îl tipărește pe o anumită imprimantă, apoi îl închide. Uau!

Sau puteți adopta o abordare mai practică, modulară și subdivizați această lungă serie de sarcini în mai multe macrocomenzi separate – câte una pentru fiecare sarcină. Dacă aceste macrocomezi trebuie să lucreze împreună ca o echipă, atunci puteți crea o altă macrocomandă care rulează fiecare dintre aceste proceduri individuale. În acest fel, puteți obține aceleași rezultate ca și utilizarea unei macrocomenzi monolitice mari. Dar codul subdivizat este mai ușor de citit, testat și uneori chiar refolosit. Gândiți-vă la asta ca la utilizarea mai multor proceduri mici, în locul unei singure proceduri mari.

Avantajele folosirii codului modular

Codul modular are mai multe avantaje față de codul care îmbină totul într-o singură macrocomandă uriașă. În primul rând, este mult mai ușor să scrieți un cod modular, deoarece creați o serie de proceduri scurte, fiecare realizând o sarcină specifică. Rămâneți concentrat pe o singură sarcină.

De asemenea, puteți depana mai ușor proceduri mici relativ, deoarece lungimea lor mai scurtă simplifică identificarea, localizarea și eliminarea erorilor. Adesea, depanarea implică aflarea exactă a problemei. Deci, cu cât sunt mai puține linii de cod care ascund eroarea, cu atât va fi mai ușor să o urmăriți.

Procedurile vor fi, de asemenea, mai lizibile și mai ușor de modificat, deoarece sunt mai puțin complexe și puteți urmări mai ușor ceea ce fac.

Codul modular este mai eficient din patru motive:

  • Prin ruperea codului în macrocomenzi multiple, care au câte un singur scop, puteți repeta sarcinile lor în diferite puncte dintr-o succesiune de proceduri, fără a fi nevoie să repetați liniile de cod. Dacă aveți mai puțin cod, procedurile sunt mai rapide.
  • Reutilizând proceduri întregi, puteți reduce cantitatea de cod care trebuie scrisă. Și scriind mai puțin cod, sunt șanse mai mici de a scrie noi erori în program.
  • Dacă trebuie schimbat un articol din cod, se face o singură modificare în procedura corespunzătoare, în loc să fie făcute modificări la un număr de locații într-o procedură lungă (și poate că lipsesc unele dintre ele). Această modificare se aplică, de asemenea, tuturor procedurilor care apelează la procedură.
  • Pot fi apelate proceduri individuale de la alte proceduri fără a fi necesar să fie asimilate cu celelalte proceduri. E mai obositor să creezi de la zero fiecare dintre funcțiile încorporate ale VBA, în loc să le poți invoca în voie. Puteți face același lucru cu funcțiile create – pot fi reutilizate în loc să reinventați roata.

Mod de abordare pentru crearea codului modular

Utilitatea codării modulare diferă de la o persoană la alta, de la proiect la proiect și de la procedură la procedură. De exemplu, la înregistrarea unei macrocomenzi pentru a efectua o sarcină simplă, o singură dată, într-o serie de prezentări, nu este nevoie de descompunerea ei în componentele sale și formarea lor ca proceduri separate. Doar se utilizează acea macrocomandă.

Însă, pentru a planifica o procedură amplă care va automatiza crearea foilor de calcul pentru estimarea bugetului companiei, poți beneficia foarte mult de împărțirea codului într-un set de mai multe proceduri. Această lucrare de automatizare este complexă și necesită mult cod, și este, de asemenea, un program care trebuie reutilizat de fiecare dată când există o nouă propunere bugetară.

Crearea codului modular se poate realiza în două moduri principale:

  • Înregistrați (dacă aplicația pe care o utilizați acceptă VBA Macro Recorder) sau scrieți o procedură ca de obicei, apoi examinați-o și împărțiți-o în module, dacă este necesar. Aceasta este o modalitate excelentă de a începe crearea codului modular, dar de obicei este mai puțin eficientă: veți ajunge să petreceți mult timp pentru a adapta procedura inițială, mare, atunci când o împărțiți în proceduri mai mici și separate.
  • Enumerați diferitele acțiuni pe care le cere proiectul, apoi codați fiecare acțiune (sau set de acțiuni) ca o procedură separată. Această metodă necesită un pic de planificare, dar, de obicei, se dovedește mai eficientă pe termen lung.

Aranjarea codului în module

După ce ați creat un set de proceduri, le puteți muta într-un nou modul în cadrul aceluiași proiect sau chiar într-un alt proiect. Prin gruparea procedurilor în module, puteți distribui cu ușurință procedurile colegilor, fără să includeți ce nu au nevoie. În plus, puteți elimina imediat din mediul de lucru orice module de cod de care nu aveți nevoie.

Dați modulelor nume sugestive

Dați modulelor denumiri sugestive, pentru a le putea identifica instantaneu în VBA Editor Project Explorer și cu alte instrumente de gestionare a modulelor. Evitați să lăsați modulele cu numele implicite Module1, Module2 etc.

Apelarea unei proceduri

Când una dintre proceduri trebuie să folosească o altă procedură scrisă deja, o apelează (după nume) în modul descris în secțiunea „Folosirea funcțiilor încorporate”, pentru a apela o funcție încorporată, cum ar fi MsgBox.

Pentru a apela o procedură în același proiect, introduceți numele procedurii pentru a fi apelată ca declarație sau utilizați instrucțiunea Call cu numele procedurii.

Sintaxa pentru comanda Call este aceeași pentru proceduri ca și pentru funcții:

[Call] name[, argumentlist]

Aici, name este argumentul obligatoriu de tip String care dă numele procedurii apelate. Și argumentlist este un argument (sau o listă cu mai multe argumente delimitate de virgule) cu variabile, tablouri sau expresii pentru a le prelua în procedură. Lista de argumente se folosește numai pentru procedurile care necesită argumente.

Apelarea implică două proceduri, apelantul și cel apelat. De exemplu, următoarea procedură CreateReceiptLetter (apelantul) apelează procedura FormatDocument (cel apelat):

Sub CreateReceiptLetter()
   'aici alte actiuni
Call FormatDocument
   'aici alte actiuni
End Sub

Majoritatea programatorilor omit cuvântul cheie Call, folosind doar numele procedurii. Următorul cod face același lucru ca și codul din exemplul anterior:

Sub CreateReceiptLetter()
   'aici alte actiuni
FormatDocument
   'aici alte actiuni
End Sub

Cu toate acestea, ca și în cazul funcțiilor încorporate, unii programatori consideră că folosirea cuvântului cheie Call poate face mai clar faptul că acel cod apelează la o procedură și permite căutarea mai ușoară a apelurilor. (La depanare, puteți vedea ce proceduri apelează pe alții, alegând opțiunea Call Stack din meniul View Editor. Această caracteristică este disponibilă doar în modul Break, însă nu în timpul proiectării.)

În exemplul următor, o procedură numită Caller apelează o procedură numită Called, care preia argumentul String strFeedMe. Rețineți că atunci când utilizați comanda Call, trebuie să adăugați lista de argumente între paranteze:

Sub Caller()
Call Called("Hello")
End Sub
Sub Called(ByVal strFeedMe As String)
Msgbox strFeedMe 
End Sub

Din nou, se poate omite cuvântul cheie Call și, dacă doriți, parantezele, și veți obține același rezultat:

Sub Caller()
Called "Hello"
End Sub

În afară de apelarea unei proceduri din același proiect, puteți apela o procedură dintr-un alt proiect deschis din aceeași aplicație gazdă (de obicei, nu dintr-o altă aplicație). În mod obișnuit, sintaxa folosită pentru apelarea unei proceduri într-un alt proiect este următoarea, deși poate varia în funcție de aplicație și versiune:

Project.Module.Procedure 

Pentru a apela o procedură dintr-un alt proiect, trebuie să adăugați o referință la acel proiect în caseta de dialog a editorilor VBA. Alegeți Instrumente> Referințe (Tools > References), selectați proiectul (clic pe butonul Browse dacă aveți nevoie să navigați la el) și apoi faceți clic pe butonul OK. După ce această referință este în vigoare, puteți apela procedura.

Referințele circulare nu sunt permise

Nu puteți adăuga la proiectul curent o referință la un proiect care în sine conține o referință la proiectul curent. Dacă încercați o referință "circulară", atunci când adăugați referința și închideți caseta de dialog References, Editorul VBA va afișa o casetă de mesaj cu avertismentul "Referință ciclică a proiectelor nepermise" (“Cyclic reference of projects not allowed”), iar editorul va refuza să insereze acea referinţă. (Totuși, se poate închide caseta de dialog References.)

Realizarea de îmbunătățiri logice la cod

Împărțirea unei proceduri mari în mai multe proceduri mai mici poate îmbunătăți logica codului dvs. forțându-vă să luați în considerare fiecare set de acțiuni pe care procedura îl are ca modul, ceea ce înseamnă că sunt separate de alte seturi de acțiuni. Și puteți îmbunătăți logica codului dvs. în alte moduri: prin utilizarea declarațiilor variabile explicite, prin eliminarea instrucțiunilor inutile pentru a simplifica codul înregistrat și cu ajutorul instrucțiunilor With pentru a elimina referințele repetitive ale obiectelor. Următoarele secțiuni descriu modalități de îmbunătățire a calității codului.

Declararea explicită a variabilelor în locul declarării implicite

Cum s-a menționat și mai înainte, se recomandă ca declararea variabileor să fie explicită:

Dim strName As String 
strName = "Ion Popescu"

Declararea implicită sare peste declararea variabilei și apoi atribuirea unei valori, care este creată implicit:

strName = "Ion Popescu"

Declarația explicită permite VBA ca să aloce doar atâta memorie cât este nevoie pentru acel tip de variabilă. Dar memoria în aceste zile este extrem de ieftină, deci nu este foarte importantă. Ceea ce este important este faptul că declarația explicită permite să evitați riscul de stocare neintenționată a tipului greșit de date în acea variabilă. Când o variabilă este declarată explicit, VBA afișează un mesaj de eroare dacă încercați să stocați tipul greșit de date în acea variabilă. Variabilele implicite sunt de tip Variant, iar cu ele VBA ar putea stoca datele greșite și va schimba pur și simplu tipul variabilei pentru a se potrivi.

Tabelul următor prezintă detaliile privind memoria folosită de diferitele tipuri de variabile.

În funcție de tipul de muncă efectuat, memoria economisită poate să difere, dacă se specifică tipurile de date și alegerea tipurilor de variabile la proceduri. De exemplu, dacă sunt stocate un milion de caractere într-o singură variabilă de tip String și nu într-o variabilă Variant, sunt economisiți 12 octeți.

Dar dacă sunt folosite mai multe variabile pe un computer cu memorie limitată, specificarea tipurilor de date corespunzătoare pentru variabile poate economisi suficientă memorie pentru a permite rularea procedurii acolo unde altfel nu ar fi capabil, sau ar putea cel puțin să fie executată mai repede. Desigur, hardware-ul se îmbunătățește continuu - iar memoria este hardware. Acum că memoria RAM devine din ce în ce mai ieftină și mai mare, conservarea memoriei nu este o problemă pentru programatori.

Un al doilea motiv pentru a declara variabilele în mod explicit, mai degrabă decât implicit este de a face codul tău mai ușor de citit și de depanat. Și un al treilea motiv este că puteți implementa unele verificări ale intervalului de rulare. Dacă știți că ceva va fi mai mic de 32.768 și, prin urmare, îl declarați ca fiind tipul de date Integer (în loc de tipul Long), veți primi automat o eroare utilă dacă în timpul execuției apare o valoare de dimensiuni mari.

Reamintim că Macro Recorder (disponibil doar în Word și Excel) oferă o modalitate excelentă de a începe să scrii cod pentru un proiect. Doar porniți Macro Recorder și efectuați acțiunile pe care doriți să le efectueze codul. Macro Recorder poate scrie cod pentru multe sarcini. Nu poate crea ramuri condiționate, bucle sau alte câteva caracteristici de cod, dar poate face totuși destul de mult.

Macro Recorder oferă o modalitate excelentă de a crea codul inițial, permițându-vă să identificați rapid obiectele încorporate cu care va trebui să lucreze procedura și metodele și proprietățile cu care va trebui să le utilizați.

Dar, după cum ați văzut, un dezavantaj al Macro Recorder este că tinde să înregistreze o mulțime de coduri de care nu aveți nevoie în realitate în proceduri: de exemplu, starea unui context - starea tuturor opțiunilor din contextul curent, mai ales dacă nu vă interesează decât una sau două opțiuni.

Este ca și cum ați face o fotografie. Aparatul foto înregistrează tot ce se află în cadru. Dar de multe ori nu vrei să vedeți totul, ci doar un anumit obiect. De exemplu, într-o fotografie cu toți copiii de pe scenă, sunteți interesat doar de zâmbetul frumos al micuței Darla și de costumul ei. Așadar, utilizați un program grafic pentru a decupa (tăia) tot, în afară de Darla.

Iată un exemplu de „decupare” a codului: Când înregistrați o procedură care schimbă o setare într-o casetă de dialog (cum ar fi trecerea la scrisul înclinat din caseta de dialog Font din Word), amintiți-vă că Macro Recorder înregistrează toate celelalte setări nu doar pe acea pagină a casetei de dialog, ci și pe toate celelalte pagini ale casetei de dialog Font (spațiul între caractere și alte lucruri de genul acesta) - ca în cazul în care le-ați fi dorit. Dar în acest caz vă interesează doar scrisul înclinat.

După ce ați terminat înregistrarea procedurii, o puteți deschide pentru a face ajustări minore; pentru a adăuga bucle, decizii sau elemente de interfață pentru utilizator (casete de mesaje, casete de introducere sau formulare); sau chiar pentru a copia părți ale codului pentru utilizare în alte proceduri. Când faceți acest lucru, examinați mai întâi codul pe care l-a înregistrat Macro Recorder și, dacă este posibil, eliminați declarațiile care nu au legătură cu scopul dvs. Lăsați doar bucățile de cod înregistrate de care aveți nevoie. Faceți codul să se concentreze pe ceea ce efectuați - sarcina pe care o îndepliniți. Mai târziu, vă veți mulțumi dacă trebuie să examinați sau să reutilizați acest cod: veți putea vedea cu ușurință ce face codul: nu superscript, nu bold, sau oricare dintre celelalte setări - doar scrisul înclinat (italic).

De exemplu, o procedură din Word. Comparați procedura Aplicare_Font_Arial care urmează cu procedura Aplicare_Font_Arial_Minimizata care vine după ea:

 Sub Aplicare_Font_Arial()
'
' Aplicare_Font_Arial
' Aplica fontul Arial la textul selectat
'
 With Selection.Font.Name = "Arial"
  .Size = 13
  .Bold = False
  .Italic = False
  .Underline = wdUnderlineNone
  .UnderlineColor = wdColorAutomatic
  .StrikeThrough = False
  .DoubleStrikeThrough = False
  .Outline = False
  .Emboss = False
  .Shadow = False
  .Hidden = False
  .SmallCaps = False
  .AllCaps = False
  .Color = wdColorAutomatic
  .Engrave = False
  .Superscript = False
  .Subscript = False
  .Spacing = 0
  .Scaling = 100
  .Position = 0
  .Kerning = 0
  .Animation = wdAnimationNone 
 End With 
End Sub

Sub Aplicare_Font_Arial_Minimizata()
  Selection.Font.Name = "Arial"
End Sub

După cum puteți vedea, codul din procedura Aplicare_Font_Arial_Minimizata are același efect ca și procedura înregistrată, dar conține doar 2 linii în loc de 31 de linii.

Folosirea comenzilor WITH pentru a simplifica codul

Când efectuați mai multe acțiuni cu un obiect, puteți utiliza adesea instrucțiuni With pentru a evita repetarea referinței obiectului pentru fiecare acțiune. Acest lucru simplifică codul. Devine mai ușor de citit. Și poate face ca acesta să funcționeze mai rapid.

De exemplu, următoarele afirmații conțin mai multe referințe la primul obiect Paragraf - Paragraphs (1) - în obiectul ActiveDocument din Word:

   ActiveDocument.Paragraphs(1).Range.Font.Bold = True 
   ActiveDocument.Paragraphs(1).Range.Font.Name = "Times New Roman" 
   ActiveDocument.Paragraphs(1).LineSpacingRule = wdLineSpaceSingle 
   ActiveDocument.Paragraphs(1).Borders(1).LineStyle = wdLineStyleDouble 
   ActiveDocument.Paragraphs(1).Borders(1).ColorIndex = wdBlue

Redundanța din cod se poate înlocui folosind structura With care face referință la obiectul Paragraphs(1) din obiectul ActiveDocument pentru a simplifica numărul de referințe implicat:

   With ActiveDocument.Paragraphs(1)
   .Range.Font.Bold = True 
   .Range.Font.Name = "Times New Roman"
   .LineSpacingRule = wdLineSpaceSingle 
   .Borders(1).LineStyle = wdLineStyleDouble 
   .Borders(1).ColorIndex = wdBlue 
   End With

Când trebuie să lucrați cu mai multe obiecte copil conținute în cadrul unui obiect părinte unic, puteți utiliza fie instrucțiuni separate With, fie să alegeți cel mai mic numitor comun al obiectelor cu care doriți să lucrați și să folosiți o instrucțiune externă împreună cu instrucțiunile imbricate pentru obiectele copil.

Dacă doriți, puteți reduce în continuare numărul de referințe la obiect din exemplul de cod anterior folosind instrucțiuni imbricate pentru obiectul Font din obiectul Range și pentru obiectul Borders(1), astfel:

With ActiveDocument.Paragraphs(1)
  With .Range.Font.Bold = True
                .Name = "Times New Roman"
  End With
  .LineSpacingRule = wdLineSpaceSingle 
  With .Borders(1)
     .LineStyle = wdLineStyleDouble
     .ColorIndex = wdBlue 
  End With 
End With

Nu folosiți declarații fără rost

Comenzile With sunt foarte bune pentru reducerea referințelor repetate la obiecte și pentru a facilita citirea codului, dar nu le folosiți doar pentru că puteți. Dacă aveți o singură declarație în cadrul unei instrucțiuni With, ca în exemplul următor (care folosește tot Word), probabil că pierdeți timpul tastând codul suplimentar pentru a configura structura With:

 With ActiveDocument.Sections(1).Headers(wdHeaderFooterPrimary) _
.Range.Words(1)
.Bold = True 
End With

În mod asemănător, nu imbricați declarațiile decât dacă trebuie – altfel, ele devin confuze, ca acest exemplu bizar:

With ActiveDocument 
 With .Sections(1)
With .Headers(wdHeaderFooterPrimary)
With .Range
With .Words(1)
 With .Font
.Italic = True 
.Bold = False 
.Color = wdColorBlack 
 End With 
End With 
End With 
End With 
 End With
End With

Acest cod este mai bun dacă este scris așa:

With ActiveDocument.Sections(1).Headers(wdHeaderFooterPrimary).Range. _ 
      Words(1).Font 
        .Italic = True 
        .Bold = False 
        .Color = wdColorBlack 
End With

Optimizarea comenzilor Select Case

Când utilizați o instrucțiune Select Case, aranjați instrucțiunile Case astfel ca cele mai probabile să apară mai întâi. Acest lucru economisește munca VBA și timpul cât VBA trece prin lista de declarații Case până găsește o potrivire, adică va găsi mai rapid o potrivire din listă, iar executarea declarației se va face mai repede.

Nu verificați inutil anumite lucruri

Dacă trebuie să implementați o setare (în special una booleană) de fiecare dată când se execută o anumită procedură, nu are rost să verificați valoarea curentă.

De exemplu, să presupunem că ați dorit să vă asigurați că este setată la True proprietatea EnableAutoRecover (o proprietate booleană care setează sau returnează dacă funcția AutoRecover este activată pentru registrul de lucru curent) al obiectului ActiveWorkbook din Excel. Puteți verifica valoarea curentă a EnableAutoRecover și, dacă este False, setați-o pe True astfel:

   If ActiveWorkbook.EnableAutoRecover = False Then _ 
    ActiveWorkbook.EnableAutoRecover = True

Dar se scrie prea mult cod. Se poate simplifica setând proprietatea la True:

ActiveWorkbook.EnableAutoRecover = True

Eliminarea elementelor nefolosite din cod

Pentru a îmbunătăți eficiența codului, încercați să eliminați din el toate elementele neutilizate. Atunci când creați un proiect complex cu multe proceduri interrelaționate, este ușor să închideți unele proceduri care sunt aproape sau total inutile. De exemplu, încercați diverse abordări și rezultate schițate într-o serie de proceduri care nu s-au mai folosit niciodată.

Veți putea să eliminați mai ușor procedurile de prisos dacă ați comentat codul în timp ce îl creați, astfel încât să puteți fi sigur că ceea ce eliminați nu este utilizat. Dacă aveți îndoieli cu privire la ce procedură apelează, afișați caseta de dialog Stack Call; alegeți View> Call Stack sau apăsați Ctrl + L pentru a vedea ce se întâmplă. De reținut: Caseta de dialog Call Stack este disponibilă în modul Break (în timp ce parcurgeți codul dintr-o procedură pas cu pas sau când VBA Editor a oprit execuția la un punct de întrerupere etc). Dacă o procedură a apelat-o pe alta în timpul executării, ambele vor fi afișate.

Alternativ, puteți încerca una din următoarele tehnici:

  • Setați un punct de întrerupere la începutul unei proceduri suspecte, astfel încât să fiți alertat atunci când este apelată.
  • Afișați casetele cu mesaje din părțile importante ale codului, astfel încât să puteți vedea ce se întâmplă: procedura este apelată vreodată?
  • Utilizați o instrucțiune Debug.Print la un moment dat (din nou, poate începutul unei proceduri) pentru a înregistra temporar informațiile în fereastra Immediate.

Înainte de a elimina o procedură aparent nefolosită din cod, asigurați-vă că nu este folosită în modulul în care se execută codul în prezent, dar și că nu este folosită în modulele în care procedura poate fi executată în alte circumstanțe. Dacă credeți că procedura poate fi folosită în continuare, încercați să o mutați într-un proiect din care să o puteți restaura cu ușurință, în loc să o ștergeți cu totul.

După ce ați eliminat toate procedurile nefolosite, examinați variabilele din proceduri. Chiar dacă utilizați declarația Option Explicit și declarați fiecare variabilă în mod explicit, verificați dacă nu ați declarat variabile care nu sunt utilizate. Pentru proiecte simple, veți putea să surprindeți variabilele neutilizate folosind fereastra Locals pentru a vedea care nu va primi niciodată o valoare. Pentru proiecte mai complexe, poate doriți să încercați unele dintre instrumentele terțe părți disponibile care vă ajută să eliminați elementele care nu sunt necesare în cod.

Dacă aveți îndoieli, utilizați funcția Find din Editor (Ctrl + F) pentru a vedea dacă numele variabilei apare o singură dată: doar când variabila este declarată.

Eliminarea procedurilor și a variabilelor neutilizate nu este crucială. Ele nu fac niciun rău real; sunt doar resturi. Însă, ele măresc codul, ceea ce îl face mai dificil de înțeles și de modificat dacă reveniți mai târziu la acesta pentru întreținere sau reutilizare.

FACEȚI COPII DE SIGURANȚĂ PENTRU MODULE, FORMULARE ȘI MODULE PENTRU CLASE

Înainte de a elimina un întreg modul, folosiți comanda Fișier> Export fișier pentru a exporta o copie a modulului într-un fișier .BAS într-o locație de stocare sigură, în cazul în care modulul conține tot ceea ce veți descoperi că are valoare. În mod similar, exportați formularele în fișiere .FRM și clasele în fișiere .CLS.

Realizarea de îmbunătățiri vizuale pentru cod

O altă modalitate de a îmbunătăți codul este de a-l formata pentru a fi ușor de citit, menținut și modificat.

Indentarea nivelurilor diferite de cod

Așa cum ați văzut în exemplele de până acum din această carte, puteți face codul mult mai ușor de urmărit prin indentarea unor linii de cod cu tab-uri sau spații pentru a arăta relația lor logică între ele sau pentru a ilustra vizual subordonarea și structurile, ca la bucle.

Puteți face clic pe butoanele Indent și Outdent de pe bara de instrumente Editare sau să apăsați Tab și Shift + Tab pentru a indenta sau a readuce rapid un bloc de cod selectat, cu aceeași indentare relativă a liniilor din bloc.

Etichetele nu pot fi Indentate, dar acesta este un lucru bun

Nu puteți indenta o etichetă - un cuvânt care se termină cu două puncte (:) și care este folosit ca țintă al unei declarații GoTo. Dacă încercați să indentați o etichetă, VBA Editor nu vă va permite. Editorul elimină toate spațiile din stânga etichetei imediat ce apăsați Enter sau mutați altfel punctul de inserție de pe linia care conține eticheta. O etichetă este o țintă și ar trebui să fie în partea stângă a liniei sale de cod, astfel încât să o puteți vedea cu ușurință.

Folosirea caracterelor de continuare a liniei pentru a întrerupe liniile lungi

Utilizați caracterul de continuare a liniei (un spațiu urmat de un caracter underscore, astfel: _) pentru a rupe liniile lungi de cod în două sau mai multe linii mai scurte. Întreruperea liniilor face ca declarațiile lungi să se încadreze în fereastra Code pe un monitor de dimensiuni medii și vă permite să scrieți codul în segmente mai logice.

Folosirea caracterului de concatenare pentru a întrerupe șirurile lungi

Cu toate acestea, nu puteți utiliza caracterul de continuare a liniei pentru a întrerupe șiruri. Dacă doriți să întrerupeți un șir lung, trebuie să împărțiți șirul în șiruri mai mici și apoi să folosiți caracterul de concatenare (&) pentru a atașa părțile din nou. Puteți separa părțile din șirul împărțit (care sunt doar separate de caracterul continuării liniei). De exemplu, ia în considerare un șir lung precum acesta:

strMessageText = "Macrocomanda s-a incheiat. Verificati prezentarea pentru a vedea daca diapozitivele goale au fost sterse."

În loc să scrieți codul pe singură linie, puteți împărți șirul în două sau mai multe linii, apoi să îl reuniți astfel:

strMessageText = "Macrocomanda s-a incheiat. " & _
"Verificati prezentarea pentru a vedea " & _
"daca diapozitivele goale au fost sterse."

Din motive legale, puteți folosi caracterul + pentru concatenare

În mod alternativ, puteți utiliza caracterul de adăugare (+) pentru a concatena un șir cu un altul, dar nu pentru a concatena un șir și o variabilă numerică (faceți asta, iar VBA va încerca să le adauge matematic în loc să le concateneze). Cu toate acestea, codul este mai ușor de citit dacă se folosește caracterul de concatenare ampersand (&) atunci când concatenează șiruri. Folosiți caracterul + pentru matematică.

Folosirea liniilor goale pentru a întrerupe codul

Pentru a face codul mai lizibil, utilizați linii necompletate pentru a separa enunțurile în grupuri logice. De exemplu, puteți separa toate declarațiile variabile dintr-o procedură așa cum se arată în exemplul următor, astfel încât acestea să se evidențieze mai clar:

Sub Create_Rejection_Letter

   Dim strApplicantFirst As String, strApplicantInitial As String, _ 
       strApplicantLast As String, strApplicantTitle As String 
   Dim strJobTitle As String
 Dim dteDateApplied As Date, dteDateInterviewed As Date 
 Dim blnExperience As Boolean
 
strApplicantFirst = "Ion" 
strApplicantInitial = "I" 
strApplicantLast = "Ionescu"

Folosirea variabilelor pentru a simplifica sintaxa complexă

Puteți utiliza variabile pentru a simplifica și a scurta sintaxa complexă. De exemplu, puteți afișa o casetă de mesaje folosind o declarație destul de lungă, cum ar fi aceasta:

If MsgBox("Documentul nu contine text." & vbCr & vbCr _
  & "Clic pe butonul Yes pentru a continua formatarea documentului." & _
  " Clic pe butonul No pentru a termina procedura.", _ 
  vbYesNo & vbQuestion, _
  "Eroare la selectarea documentului: Terminare Procedura?") Then

Alternativ, puteți folosi o variabilă de tip String pentru a construi mesajul și o altă variabilă String pentru titlu:

Dim strMsg As String 
Dim strTBar As String
strMsg = "Documentul nu contine text." & vbCr & vbCr strMsg = _
strMsg & "Clic pe butonul Yes pentru a continua formatarea documentului. " 
strMsg = strMsg & "Clic pe butonul No pentru a termina procedura." 
strTBar = "Eroare la selectarea documentului: Terminare Procedura?"
If MsgBox(strMsg, vbYesNo & vbQuestion, strTBar) Then

La prima vedere, acest cod arată mai complex decât declarația simplă a casetei de mesaje, mai ales datorită declarațiilor variabile explicite care măresc lungimea segmentului de cod. Dar pe termen lung, această abordare este mult mai ușor de citit și de modificat.

În exemplul anterior, puteți înlocui, de asemenea, partea vbYesNo & vbQuestion din instrucțiunea MsgBox cu o variabilă (de preferință de tip Long, nu Variant). Dar acest lucru ar face codul mai greu de citit și rareori merită să fie folosit.

Trecerea informației de la o Procedură la alta folosind argumente

Adesea, atunci când apelați o altă procedură, va trebui să îi transmiteți informații din procedura de apelare. Și uneori, invers: atunci când procedura apelată s-a terminat de executat, trebuie să transmită informațiile apelantului.

Reamintim că modalitatea des folosită de a transmite informațiile de la o procedură apelantă la o procedură apelată este folosind argumentele. Declarați argumentele care vor fi transmise în linia de declarație a procedurii care le transmite. Argumentele apar în paranteze după numele procedurii. Puteți trece fie un singur argument (așa cum face prima dintre următoarele afirmații) sau mai multe argumente separate prin virgule (așa cum face a doua):

Sub TransmitereUnArgument(UnArg)
Sub TreansmitereDouaArgumente(PrimulArg, AlDoileaArg)

Ca și în cazul funcțiilor (discutate în secțiunea Folosirea funcțiilor încorporate), puteți trece un argument fie prin referință, fie ca valoare. Când o procedură trece un argument la o altă procedură prin referință, procedura destinatarului primește acces la locația de memorie în care este stocată variabila inițială și poate schimba variabila inițială. În schimb, când o procedură transmite un argument unei alte proceduri prin valoare, procedura destinatarului primește doar o copie a informațiilor din variabilă și nu poate modifica informațiile din variabila inițială.

Trecerea unui argument prin referință este utilă atunci când doriți să manipulați variabila în procedura destinatarului și apoi să returnați variabila la procedura de la care a provenit. Trecerea unui argument prin valoare este utilă atunci când doriți să utilizați informațiile stocate în variabilă în procedura destinatarului și, în același timp, să vă asigurați că informațiile originale din variabilă nu se modifică.

Prin referință, este modul implicit de a trece un argument, dar puteți utiliza, de asemenea, cuvântul cheie ByRef pentru a afirma explicit că doriți să treceți un argument prin referință. Ambele dintre următoarele afirmații transmit argumentul MyArg prin referință:

Sub PassByReference(MyArg)
Sub PassByReference(ByRef MyArg)

Pentru a transmite un argument prin valoare, trebuie să folosiți cuvântul cheie ByVal. Următoarea comandă transmite argumentul ValArg prin valoare:

Sub PassByValue(ByVal ValArg)

Totuși, în practică, se va transmite rareori prin valoare - ByVal. Argumentele sunt aproape universal trecute prin referință, implicit.

Dacă este necesar, puteți trece unele argumente pentru o procedură prin referință și altele prin valoare. Următoarea declarație trece argumentul MyArg prin referință și argumentul ValArg prin valoare:

Sub PassBoth(ByRef MyArg, ByVal ValArg)

Puteți declara în mod explicit tipul de argumente pe care le transmiteți pentru a folosi mai puțină memorie și pentru a vă asigura că procedurile transmit tipul de informații pe care le intenționați. Dar când treceți un argument prin referință, trebuie să vă asigurați că tipul de date al argumentului pe care îl transmite se potrivește cu tipul de date preconizat de procedura apelată. De exemplu, dacă declarați un șir în procedura apelantului și încercați să-l transmiteți ca argument atunci când procedura apelată așteaptă un Variant, VBA afișează o eroare.

Pentru a declara tipul de date al unui argument, includeți o declarație de tip date în lista de argumente. Următoarea declarație declară MyArg ca String și ValArg ca Variant:

Sub PassBoth(MyArg As String, ValArg As Variant)

Puteți specifica un argument opțional folosind cuvântul cheie Optional. Plasați cuvântul cheie Optional înainte de cuvintele cheie ByRef sau ByVal dacă doriți să utilizați ByRef sau ByVal:

Sub PassBoth(ByRef MyArg As String, ByVal ValArg As Variant, _
      Optional ByVal MyOptArg As Variant)

Mai jos este prezentat un segment dintr-o procedură care folosește argumente pentru a transmite informația de la o procedură la alta.

1. Sub PreluareInfoClient()
2.    Dim strNumeClient As String, strOrasClient As String, _
          strTelClient As String
3.  'Preia strNumeClient, strOrasClient, strTelClient dintr-o baza de date
4.    CreareClient strNumeClient, strOrasClient, strTelClient
5. End Sub
6.
7. Sub CreareClient(ByRef strNumeC As String, _
      ByRef strOrasC As String, ByVal strTelC As String)
8.  Dim strClient As String
9.  strClient = strNumeC & vbTab & strOrasC _
      & vbTab & strTelC
10.  'aici face operatiuni cu strClient
11. End Sub
  • Prima procedură, PreluareInfoClient, declară în mod explicit pe linia 2 trei variabile de tip String: strNumeClient, strOrasClient și strTelClient.
  • Linia 3 conține un comentariu care indică faptul că aici se poate scrie un cod suplimentar pentru a obține datele și a atribui informații pentru variabile.
  • Linia 4 apelează procedura CreareClient și trece la aceasta variabilele strNumeClient, strOrasClient și strTelClient ca argumente. Deoarece această afirmație nu utilizează cuvântul cheie Call, argumentele nu sunt incluse în paranteze.
  • Execuția trece apoi la linia 7, care începe procedura CreareClient prin declararea celor trei argumente String pe care le folosește: strNumeC și strOrasC care trebuie trecute prin referință, iar strTelC care trebuie trecut prin valoare.
  • Linia 8 declară variabila strClient de tip String. Linia 9 atribuie apoi la strClient informațiile din strNumeC, un caracter Tab, informațiile din strOrasC, alt Tab și informațiile din strTelC.
  • Linia 10 conține un comentariu care indică cum ar putea acționa procedura cu șirul strClient (de exemplu, adăugarea acesteia într-un fel de bază de date primitivă), iar linia 11 încheie procedura.

Transmiterea informației înapoi de la o procedură apelată

De reținut: doar funcțiile, nu și subrutinele, sunt utilizate pentru a transmite informațiile către un apelant. Funcțiile și subrutinele sunt ambele proceduri, dar numai funcțiile sunt proiectate special pentru a trimite informații înapoi către apelant.

Acest exemplu de cod apelează o funcție care adaugă impozitul la un preț de achiziție și apoi întoarce costul total rezultat:

1. Sub CalculCostTotal()
2.
3.    Dim OriginalCost, TotalCost ' declara doua variabile de tip Variant
4.    OriginalCost = 155 ' valoarea pentru cost
5.
6.    TotalCost = AdaugTaxa(OriginalCost) 'apeleaza functia AdaugTaxa
7.    MsgBox TotalCost 'afiseaza costul final, inclusiv taxa de 7%
8.
9.
10. End Sub
11.
12. Function AdaugTaxa(SubTotal)
13.
14.  AdaugTaxa = SubTotal * 1.07 'face calcule pentru a adauga rezultatul
15.                             'la numele functiei pentru a returna rezultatul
16.
16. End Function

Pe linia 6, datele sunt transmise de la apelant la apelat. Pe linia 14, informațiile sunt transmise înapoi de la apelat către apelant, alocând o valoare numelui funcției.

Transmiterea informației de la o procedură la alta folosind variabilele Private sau Public

Un alt mod de a transmite informațiile de la o procedură la alta este folosind variabile private sau publice (cunoscute și sub denumirea de variabile globale, spre deosebire de variabilele locale pentru procedurile individuale). Puteți utiliza variabile private dacă procedurile care trebuie să partajeze informații sunt localizate în același modul. Dacă procedurile sunt localizate în module diferite, va trebui să utilizați variabile publice pentru a transmite informațiile.

Evitarea folosirii de variabile Globale pentru a transmite informații

Utilizarea variabilelor private sau publice pentru a transmite informații de la o procedură la alta este considerată pe scară largă o practică slabă de programare. Făcând acest lucru, este mai dificil să urmăriți fluxul de informații între proceduri, mai ales atunci când sunt implicate mai multe proceduri. Cu toate acestea, este posibil să găsiți uneori utilă această modalitate de transmitere a informațiilor sau să vi se solicite să lucrați cu codul altcuiva care utilizează această abordare.

Codul de mai jos conține un exemplu de transmitere a informațiilor prin utilizarea de variabile private.

1. Private strPassMe As String
2.  
3. Sub PassingInfo()
4.  strPassMe = "Salut."
5.  PassingInfoBack
6.  MsgBox strPassMe
7. End Sub
8.  
9. Sub PassingInfoBack()
10.  strPassMe = strPassMe & " Ce mai faci?"
11. End Sub

Codul începe prin declararea la început a variabilei private StPassMe de tip String. strPassMe este apoi disponibil pentru toate procedurile din modul.

  • La linia 4, procedura PassingInfo (liniile 3 - 7) atribuie textul Salut. (cu punct) variabilei strPassMe, apoi apelează procedura PassingInfoBack la linia 5.
  • Execuția trece apoi la linia 9, care începe procedura PassingInfoBack.
  • Linia 10 adaugă la variabila strPassMe șirul de caractere Ce mai faci?, de tip String, cu un spațiu înainte.
  • Linia 11 încheie procedura PassingInfoBack, moment în care execuția revine la procedura PassingInfo la linia 6, care afișează o casetă de mesaj care conține șirul strPassMe (acum Salut. Ce mai faci?).
  • Linia 7 încheie procedura.