Het gebruik van de Controls Collection

Regelmatig ontvang ik stukjes source-code waarbij mijn mening wordt gevraagd. Wat daarbij opvalt is dat het gebruik van de Controls Collection niet veel wordt gebruikt. Zie het volgende voorbeeld:
Sub Form_Load()
 txtName.Text = ""
 txtAdress.Text = ""
 txtZipCode.Text =""
 txtPlace.Text =""
End Sub
De bedoeling is duidelijk: de maker wil dat als het form wordt geladen de vier aanwezige textboxen leeg worden getoond. Als deze actie zich echter vaker kan voordoen (bijvoorbeeld onder een Cancel-button) dan moet je dezelfde code al meerdere keren invoeren. Je kan er voor kiezen om er een aparte procedure van te maken:
Sub LeegTextBox()
 txtName.Text = ""
 txtAdress.Text = ""
 txtZipCode.Text =""
 txtPlace.Text =""
End Sub
Dan zet je in elke event die de textboxen leeg moet tonen de code:
Sub Form_Load()
 Call LeegTextBox
End Sub

Sub cmdCancel_Click()
 Call LeegTextBox
End Sub
Je kunt dit nog verder versimpelen door gebruik te maken van de Controls.Collection:
Sub LeegTextBox()
 Dim Control
 
 For Each Control In Me.Controls
  If TypeOf Control Is TextBox Then Control.Text = ""
 Next Control
End Sub
Om het helemaal ‘goed’ te doen maak je er een (op een module) publieke procedure van en geef je nog aan van welke form de textboxen moeten worden geleegd:
Public Sub LeegTextBox(X as Form)
 Dim Cntr
 
 For Each Cntr In X.Controls
  If TypeOf Cntr Is TextBox Then X.Cntr.Text = ""
 Next Cntr
End Sub
Aanroepen gebeurt dan op de volgende manier:
Sub Form_Load()
 Call LeegTextBox(Me)
End Sub
Dit kan dan vanaf elk willekeurig formulier en elke event gebeuren. Je kunt natuurlijk elke andere property op deze manier wijzigen. Je kunt tenslotte ook elke control aanroepen. Dit doe je met het TypeOf commando

Het gebruik van indexed controls

Het gebruik van indexed controls heeft als voordeel dat je niet telkens dezelfde code onder dezelfde events van gelijksoortige controls hoeft te plaatsen. Stel je hebt vijf textboxen waar je de volgende gegevens wil laten invoeren:
 voornaam   (name = txtVoornaam)
 achternaam (name = txtAchternaam)
 adres      (name = txtAdres)
 postcode   (name = txtPostcode)
 woonplaats (name = txtWoonplaats)
Van de invoer in de eerste drie textboxen wil je automatisch de eerste letter van elk woord omzetten in een hoofdletter; van de laatste twee textboxen wil je de invoer in zijn geheel omzetten naar hoofdletters. Kies je ervoor om elke textbox een aparte naam te geven (voor de duidelijkheid is dat wel een goede zaak) dan ziet je code er ongeveer zo uit :
Sub txtVoornaam_LostFocus()
 txtVoornaam.Text = StrConv(txtVoornaam.Text, vbProperCase)
End Sub

Sub txtAchternaam_LostFocus()
 txtAchternaam.Text = StrConv(txtAchternaam.Text, vbProperCase)
End Sub

Sub txtAdres_LostFocus()
 txtAdres.text = StrConv(txtAdres.Text, vbProperCase)
End Sub

Sub txtPostcode_LostFocus()
 txtPostcode.Text = UCase$(txtPostode.Text)
End Sub

Sub txtWoonplaats_LostFocus()
 txtWoonplaats.Text = Ucase$(txtWoonplaats.Text)
End Sub
Maak je gebruik van indexed textboxen dan ziet het er zo uit:
 voornaam    (name = txtInvoer; index = 0)
 achternaam  (name = txtInvoer; index = 1)
 adres       (name = txtInvoer; index = 2)
 postcode    (name = txtInvoer; index = 3)
 woonplaats  (name = txtInvoer; index = 4)
Sub TxtInvoer_LostFocus(Index As Integer)
 Select Case Index
 Case 0, 1, 2
  TxtInvoer(Index).Text = StrConv(TxtInvoer(Index).Text,vbProperCase)
 Case 3,4
  TxtInvoer(Index).Text = UCase$(TxtInvoer(Index).Text)
 End Select
End Sub
Dat scheelt toch wel een hoop type-werk! Nog steeds kun je de voorgaande manier gebruiken om alle textboxen in een keer te legen (er verandert niets aan het soort control wat je gebruikt). Het gebruik van indexed controls gaat meestal samen met het gebruik van de Select Case commando’s.
Een ander voorbeeld waarbij het gebruik van indexed controls erg makkelijk is. Iedereen gebruikt weleens commandobuttons. Stel je hebt vijf knoppen:
 Nieuw     (name = cmdKnop; index = 0)
 Wijzigen  (name = cmdKnop; index = 1)
 Bewaren   (name = cmdKnop; index = 2)
 Verwijder (name = cmdKnop; index = 3)
 Stoppen   (name = cmdKnop; index = 4)
De code ziet er dan ongeveer zo uit:
Sub cmdKnop_Click(Index As Integer)
 Select Case Index
  Case 0 ‘code om een item toe te voegen
  Case 1 ‘Code om een item te wijzigen
  Case 2 ‘Code om een item te bewaren
  Case 3 ‘Code om een item te verwijderen
  Case 4
   Unload Me
 End Select
End Sub
Wat je graag zou willen is dat je gebruikers niet tegelijkertijd kunnen toevoegen en verwijderen met andere woorden je wil de mogelijkheid hebben om commandoknoppen te ‘disablen’. Als er een item wordt toegevoegd moeten de knoppen ‘Wijzigen’ en ‘Verwijderen’ niet ter beschikking staan. Na het bewaren moeten ze weer toegankelijk zijn. Het komt er dan ongeveer zo uit te zien:
Sub cmdKnop_Click(Index As Integer)
 Select Case Index
  Case 0 ‘nieuw
    cmdKnop(1).Enabled = False
    cmdKnop(3).Enabled = False
    ‘code om een item toe te voegen
  Case 1 ‘wijzigen
    ‘Code om een item te wijzigen
  Case 2 ‘bewaren
    ‘Code om een item te bewaren
    cmdKnop(1).Enabled = True
    cmdKnop(3).Enabled = True
  Case 3 'verwijderen
    ‘Code om een item te verwijderen
  Case 4 ‘stoppen
    Unload Me
 End Select
End Sub
Dit kan natuurlijk met minder werk. In plaats van per commandoknop de overige knoppen aan of uit te zetten geef je een regel code in:
Sub cmdKnop_Click(Index As Integer)
 Select Case Index
  Case 0 ‘nieuw
   Call SetCommand("10101")
   'code om een item toe te voegen
  Case 1 ‘wijzigen
   ‘Code om een item te wijzigen
  Case 2 ‘bewaren
   ‘Code om een item te bewaren
   Call SetCommand("11111")
  Case 3 'verwijderen
   ‘Code om een item te verwijderen
  Case 4 ‘stoppen
   Unload Me
 End Select
End Sub

Sub SetCommand(which As String)
 Dim lngX As Long
 For lngX = 1 To Len(which)
  If Mid(which, lngX, 1) = 0 Then 
   Me.cmdKnop(lngX - 1).Enabled = False 
  Else 
   Me.cmdKnop(lngX - 1).Enabled = True
  End If
 Next lngX
End Sub
Wat de procedure SetCommand doet is per karakter controleren of het een ‘1' of een ‘0' is. Aan de hand van de waarde en van de plaats in de string (‘which’) wordt de betreffende commandoknop toegankelijk (of niet). Ook deze procedure kun je aanpassen voor gebruik bij meerdere formulieren:
Sub SetCommand(which As String, X As Form)
 Dim lngX As Long
 For lngX = 1 To Len(which)
  If Mid(which, lngX, 1) = 0 Then 
   X.cmdKnop(lngX - 1).Enabled = False 
  Else 
   X.cmdKnop(lngX - 1).Enabled = True
  End If
 Next lngX
End Sub
De aanroep wordt dan: Call SetCommand("11111", Me)

http://www.kather.net/VisualBasicSource/
[gepubliceerd in kwartaalblad van de Visual Basic Groep NL: Visual Basic Magazine; juni 1998 jaargang 4, nr. 2]