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:

  1. Maak een macro om de cellen A1:A10 op te vullen met willekeurige, gehele getallen tussen 0 en 200. Kleur de achtergrond rood indien de inhoud van de cel groter is dan 100, anders groen.
  2. Maak een macro om de cellen A1:A10 op te vullen met willekeurige, gehele getallen tussen 10 en 40. Kleur nadien het grootste rood en het kleinste groen..
  3. Maak een macro om een omrekeningstabel van Celsius naar Farhrenheit te maken. Tik de kleinste en de grootste Celsiuswaarde eerst in.
  4. Maak een macro om de nnam van de eerste dag van elke maand af te drukken. Het jaartal wordt eerst ingetikt in een invoervenster.
  5. Maak een macro om de even rijen tot rij 20 blauw te kleuren.
  6. Maak een macro om een weekrooster aan te leggen waarbij voor elke dag en elk uur een cel voorzien is. Plaats de namen van de dagen op rij 1 vanaf B1 en de uren in kolom A vanaf A2. Laat de uren variëren van 8 tot 17. Kleur de middagpauze (12.00 tot 13.00) groen).

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
      instructies
Next element

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
            instructies
Loop While | Until voorwaarde]

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:

  1. Plaats in kolom A vanaf A1 willekeurige getallen (1-20) tot wanneer de som ervan groter is dan 100. Zet de som onder de getallen. Gebruik de functie RND.
  2. Druk in een 'messagebox' waneer de derde zondag na nieuwjaar valt?
  3. Stel je volgt een cursus elke derde dinsdag van de maand van maart tot juni. Druk de date af in kolom A vanaf A1.