8.7 Variabelen en controlestructuren
8.7.1 Variabelen
8.7.1.1 Gegevenvariabelen
| Niet alle gegevens die je in een module gebruikt staan in cellen van een werkblad. Gegevens kunnen ook 'onthouden' worden in benoemde geheugenplaatsen. Je moet deze eerst aanmaken met de instructie DIM en erbij vertellen van welke soort de gegevens zullen zijn die je er in wil opslaan. Je kan dus van alle bestaande gegeventypes geheugenvariabelen maken. | Je wijst een waarde toe aan een gegevenvariabele met de toewijzingsopdracht. Daarbij mag je het woord LET vooraan schrijven. Eens een variabele een waarde heeft kan je naar de inhoud verwijzen via de naam. Je kan de inhoud van een varibele op elk moment wijzigen. |
| Dim strNaam as String Dim intPrijs as Integer Dim dtmLevering as Date |
Let strNaam =
"Janssens" intPrijs = 250 * ActiveCell.Value dtmLevering = Inputbox("Tik de datum in" ) |
opmerking: op het vlak van 'levensduur' en 'reikwijdte' onderscheidt men lokale, publieke en statische variabelen. Voorlopig houden we het bij lokale variabelen. Deze worden gecreëerd in een subprocedure of subfunctie en zijn enkel binnen daarin gekend.
8.7.1.2 Objectvariabelen
| Terwijl je in een gegevenvariabele gegevens stockeert, verwijs je via een objectvariabele naar een object. Je creëert zo'n variabele eveneens met de DIM-instructie. Je kan dus een objectvariabele creëren voor elk objecttype. | De verwijzing naar een object gebeurt met de opdracht SET. Je slaat een object niet op in een variabele, je verwijst er alleen naar via de variabelenaam.Je kan dan de variabelenaam gebruiken i.p.v. de objectaanduiding zelf. |
| Dim verkoop as Range | Set verkoop
= range("A1:B10") verkoop.Borders.Font.Bold = True |
8.7.2 Controlestructuren
8.7.2.1 Bepaling
De mogelijkheden van opgenomen macro's zijn beperkt . Een dergelijke macro voert 'blind' uit wat is geregistreerd. Controlestructuren laten je toe macro's te schrijven die zich tijdens de uitvoering aanpassen aan de omstandigheden! Vooreerst kan je in een macro de selectiestructuur gebruiken. Daardoor kan je in een macro testen laten uitvoeren die het verdere verloop beïnvloeden. Ook kan je de iteratiestrucuur of herhaling of lus gebruiken. Daarmee is het mogelijk de macro of een deel ervan meerdere keren te laten uitvoeren, desgewenst telkens met aangepaste gegevens.
De flexibiliteit van macro's kan nog verhoogd worden door het gebruik van parameters. Dit komt later aan bod.
| Controlestructuren kunnen niet opgenomen worden en moet je dus zelf schrijven! |
8.7.2.2 Voorbeeld
| Onderstaande macro kleurt de achtergrond van de cellen A1 tot A10 afwisselend blauw en rood. |
| Sub Kleuren() Dim intTel As Integer Range("A1").Select For intTel = 1 To 10 If intTel Mod 2 = 0 Then ActiveCell.Interior.Color = RGB(255, 0, 0) Else ActiveCell.Interior.Color = RGB(0, 0, 255) End If ActiveCell.Offset(1, 0).Select Next intTel End Sub |
Bespreking:
Door de opdracht For intTel = 1 To 10 worden aan de variabele intTel achtereenvolgens de waarden van 1 tot 10 toegewezen. Terwijl intTel de waarde 1 heeft worden de opdrachten tussen For ... en Next ... uitgevoerd. Dan wordt de waarde van intTel met 1 verhoogd en wordt gecontroleerd of de waarde niet boven 10 uitkomt. Indien niet worden de opdrachten tussen For en Next herhaald. Deze opdrachten worden in het voorbeeld dus 10 keer herhaald. Je kan de For-instructie beschouwen als een herhaalde LET-instructie.
| Syntax van de iteratiestructuur For Next: For <telvariabele> = <beginwaarde> to <eindwaarde> [step <stapwaarde>] opdrachten die herhaald moeten worden Next <telvariabele> De telvariabele is van een numeriek type (integer, long, single...). De beginwaarde, de eindwaarde en de stap moeten numerieke expressies zijn. De eindwaarde moet tenminste even groot zijn als de beginwaarde tenzij de stap negatief is. De opdrachten tussen For en Next worden herhaald tot wanneer de eindwaarde is overschreden. |
Een selectie heeft een 'ja-tak' en een 'neen-tak'. De 'ja-tak' bevat de opdrachten die moeten uitgevoerd worden indien aan de voorwaarde achter If voldaan is, de 'neen-tak' de opdrachten die moeten uitgevoerd worden indien aan de voorwaarde achter If niet voldaan is.
| Syntax van de selectiestructuur: If <voorwaarde> then opdrachten uit te voeren indien aan voorwaarde voldaan is else opdrachten uit te voeren indien aan voorwaarde niet voldaan is end if |
Een voorwaarde in een selectiestructuur levert steeds één van twee antwoorden op: waar of niet waar. In het voorbeeld wordt gevraagd of de waarde van de variabele intTel even is. Dit gebeurt met de MOD-operator.
Voorbeelden van voorwaarden na If:
Je kan samengestelde voorwaarden schrijven door gebruik te maken van de logische of Booleaanse operatoren AND, OR en NOT.
Voorbeelden:
Oefeningen:
8.7.2.2 Geneste structuren
Binnen een lus kan nog een lus voorkomen. Dit zijn geneste lussen. Hetzelfde geldt voor een selectie. In principe is er geen beperking voor de 'diepte' van het nesten. In de praktijk blijkt nesten van structuren tot 3 niveaus het maximum dat hanteerbaar is.
Voorbeeld geneste selecties:
| Sub xx() Dim strInvoer As String strInvoer = InputBox("Tik een getal in a.u.b.") If IsNumeric(strInvoer) Then If Val(strInvoer) > 0 Then MsgBox ("Positief.") Else MsgBox ("Negatief.") End If Else MsgBox ("Geen getal") End If End Sub |
Tik een waarde in en druk af
of het een getal is. Zo ja, druk af of het positief of
negatief is. Aangezien er hier 3 mogelijkheden zijn, volstaat één selectie niet. Op de 'ja-tak' van de eerste selectie ligt nog een selectie. tip: schrijf de bij elkaar horende if - else - endif precies onder elkaar met dezelfde insprong. Dit helpt bij het zoeken naar fouten!! |
Voorbeeld geneste lussen:
| Onderstaand voorbeeld schrijft de getallen van 1 tot 100 in rijen van 10 vanaf A1. De veelvouden van 5 worden rood gekleurd, de veelvouden van 7 groen en de andere getallen blauw. Hier komt zowel het nesten van lussen als van selecties in voor. |
| Dim intRij, intKolom, intGetal As Integer For intRij = 0 To 9 For intKolom = 1 To 10 intGetal = intRij * 10 + intKolom Cells(intRij + 1, intKolom).Value = intGetal If intGetal Mod 5 = 0 Then Cells(intRij + 1, intKolom).Font.Color = RGB(255, 0, 0) Else If intGetal Mod 7 = 0 Then Cells(intRij + 1, intKolom).Font.Color = RGB(0, 255, 0) Else Cells(intRij + 1, intKolom).Font.Color = RGB(0, 0, 255) End If End If Next intKolom Next intRij |
8.7.2.3 De meervoudige selectie
Het nesten van selecties is praktisch beperkt. Bij het nesten tot de vierde graad of meer begrijp je nauwelijks nog wat je eigenlijk schrijft. De meervoudige selectie biedt voor testen met veel mogelijke antwoorden een oplossing.
| Select Case WeekDay(Date, vbMonday) Case 1 MsgBox (strTekst + "tomatensoep.") Case 2 MsgBox (strTekst + "uiensoep.") Case 3 MsgBox (strTekst + "wortelsoep.") Case 4 MsgBox (strTekst + "groentensoep.") Case 5 MsgBox (strTekst + "preisoep.") Case 6 MsgBox (strTekst + "witloofsoep.") Case 7 MsgBox (strTekst + "erwtensoep.") End Select |
De structuur hiernaast
bepaalt aan de hand van de dag van de week welke soep je
eet. De 7 mogelijkheden moeten uiteraard opgesomd worden,
doch er is geen geneste structuur. De functie Weekday toegepast op een datum levert een getal (1-7) dat de dag van de week aanduidt. De tweede (optionele) parameter geeft aan op welke dag de week moet beginnen. De standaardwaarde is zondag! Met het cijfer 2 of de symbolische constante 'vbMonday' als tweede parameter is maandag de eerste dag van de week. |
| Syntaxis: Select Case testexpressie Case expressielijst 1 instructies 1 Case expressielijst 2 instructies 2 Case expressielijst n-1 instructies n-1 Case Else instructies n End Select |
De reeks opdrachten
<instructies 1> wordt uitgevoerd indien
<testexpressie> gelijk is aan één van de waarden
uit <expressielijst 1>. De reeks opdrachten <instructies n> wordt uitgevoerd indien <testexpressie> aan géén van de waarden uit de vorige expressielijsten gelijk is. Hiermee kan je dus voor alle niet voorziene (bijvoorbeeld foutieve) waarden een passende reactie (bijvoorbeeld foutboodschap) geven. Van alle opgesomde mogelijkheden wordt er tenhoogste één uitgevoerd! Is bijvoorbeeld het derde geval waar en het zesde ook, dan worden enkel de opdrachten bij het derde uitgevoerd! Indien je Case Else gebruikt moet je deze instructie logischerwijze als laatste in de reeks plaatsen! |
| Enkele voorbeelden van toegelaten
expressielijsten Select Case intGetal Case Is = 1 .... Case 2 To 4 .... Case 5, 7, 9 To 13 .... Case Is <> 2 .... Case 4 To 7 Or intGetal > -4 .... Case 8, 12, 14 .... Case 1 To 4, 7, Is > MaxNumber .... Case Else .... End Select |
Het sleutelwoord Is
kan je gebruiken met een vergelijkingsoperator. Je mag
het evenwel weglaten. Met het sleutelwoord To geef je een bereik met waarden op. De kleinste waarde moet vooraan staan. Tussen de expressies schrijf je een komma. Het type van een expressie achter Case moet hetzelfde zijn als het type van de testexpressie achter Select. |
8.7.2.4 Verzamelingen manipuleren met de For Each-instructie
Voorbeeld 1:
Worksheets is een eigenschap van het Application-object en van het Workbook-object en levert als resultaat de verzameling van alle werkbladen van de actieve werkmap op. Onderstaande macro toont de namen van alle werkbladen na elkaar.
| Sub xx() Dim wrk As Worksheet For Each wrk In Worksheets MsgBox wrk.Name Next wrk End Sub |
Je maakt een objectvariabele van het type Worksheet en gebruikt deze als 'teller' om alle elementen van de verzameling aan te spreken met de For Each-instructie. Je hoeft dus zelf niet te weten hoeveel elementen de verzameling momenteel bevat. |
De For Each-instructie kan je beschouwen als een herhaalde SET-instructie.
| Syntax: For Each
element In groep |
Voorbeeld 2:
Een celbereik is een verzameling van cellen. Je kan dus de For Each-instructie gebruiken om alle cellen van een bereik aan te spreken. Het voorbeeld telt van hoeveel cellen van het bereik A10:D20 de inhoud groter is dan 10.
| Sub xx() Dim Cel, Bereik As Range, intTel As Integer intTel = 0 Set Bereik = Range("A10:D20") For Each Cel In Bereik If Cel.Value > 10 Then intTel = intTel + 1 End If Next Cel MsgBox CStr(intTel) + " op " + CStr(Bereik.Count) End Sub |
Een verzameling heeft altijd
de eigenschap Count. De waarde daarvan
geeft aan uit hoeveel elementen de verzameling bestaat. In het uitvoervenster wordt een 'stringexpressie' gevormd. De 2 getalwaarden die erin voorkomen moeten eerst geconverteerd worden naar het type string. Dit gebeurt met de functie CStr. |
8.7.2.5 Voorwaardelijke lussen
De For Next-instructie en de For Each-instructie hebben als gemeenschapppelijk kenmerk dat het aantal keer dat de lus doorlopen wordt vastligt bij de start. Soms moeten instructies een aantal maal herhaald worden zonder bij de aanvang te kunnen bepalen hoeveel keer. In onderstaand voorbeeld wordt een maandkalender gemaakt in kolom A.. Eerst wordt gevraagd voor welke maand van het huidig jaar je een kalender wil maken.
| Sub xx() Dim dtmStart, dtmTel As Date Dim strInvoer As String strInvoer = InputBox("Maand (1-12)") dtmStart = DateSerial(Year(Now()), CInt(strInvoer), 1) dtmTel = dtmStart Range("A1").Activate Do ActiveCell.Formula = dtmTel dtmTel = dtmTel + 1 ActiveCell.Offset(1, 0).Activate Loop Until Month(dtmTel) <> Month(dtmStart) End Sub |
Alle opdrachten tussen Do
en Loop Until worden herhaald tot
wanneer aan de voorwaarde achter Until is voldaan. Het aantal keer dat de lus doorlopen wordt hangt dus af van het aantal dagen dat de betrokken maand telt. De lus in het voorbeeld stopt vooraleer de eerste dag van de volgende maand afgedrukt wordt. |
In plaats van Loop Until kan je ook Loop While gebruiken. De voorwaarde kan achter Do of achter Loop While/Until staan. Dit betekent dat van de 'Do-lus' 4 varianten bestaan.
| Syntaxis: Do While | Until voorwaarde instructies Loop Do |
Een lus met While wordt herhaald zolang aan de voorwaarde voldaan is; een lus met Until wordt herhaald tot wanneer aan de voorwaarde voldaan is.
| Sub xx() Dim intTel As Integer intTel = 1 Do Cells(intTel, 1).Formula = intTel * 2 intTel = intTel + 1 Loop While intTel <= 10 End Sub |
Met een Do...Loop-instructie kan je uiteraard ook een 'gewone' lus met een teller vormen. Je hebt dan een equivalent voor de For..Next-instructie. Je moet dan op een afzonderlijke regel de beginwaarde van de teller instellen en in de lus de tellerwaarde veranderen. Wordt dit laatste vergeten dan heb je een oneindige lus! |
Oefeningen: