Control Arrays: What, Why and How

BillSoo
07-13-2001, 12:46 PM
The following is a topic authoured by Karimahta:

What are Control Arrays?
Just as you can have an array of numbers, strings, variants or even objects in your code, Visual Basic also allows you to have arrays of controls on your form.

The easiest way to see this in action is to open VB and and create a new empty project.
...
Yes go on do it now....

OK, now draw a control, let's use a textbox, onto the current form.
Name the text box control txtField
Check the value of Index property. It should be blank.

Now click on the textbox and press CTRL + C (Copy) and then CTRL +V (Paste).
VB should now prompt you with a question asking if you want to convert this control to a control array. Click Yes then repeat the whole process so that you have two new textboxes on the screen. (Make sure you move them away from the centre as they will be one on top of the other)

Note check the property screen for each control noting the Index property for each. They should be numbered 0 to 2.
Note that the textboxes all have the same name.
images/smilies/cool.gifCool, you have now created a control array.

You can also create a control array by changing one control's name to another's (they must be the same type though.)
VB will ask you the magic question again.

You can also just put a number in the Index property and turn that control into a control array.


How do you access a Control Array in code?
Double click on one of the textboxes in the control array on the form.
This should open the form's code module window and display the text box's Change event. It should look like this...
Private Sub txtField_Change(Index As Integer)

End Sub
Notice that there is a new argument in the change event declaration, Index. For a normal text box, this is empty.
This is how you access each individual control in a control array, exactly like any other array in VB.
E.G. To change the second (index = 1) text box's background colour:
Me.txtField(1).BackColor = vbRed
Also notice how when you just type the Me.txtField you get a set of methods that relate to the control array giving you the upper and lower bounds of the control array and the number of controls in it. So you could loop through a control array and change all the background colours to Yellow like this:

Dim lngIndex As Long

For lngIndex = Me.txtField.LBound To Me.txtField.UBound
' Colour the background of each 'Field' text box
Me.txtField(lngIndex).BackColor = vbYellow
Next lngIndex

However there is a problem with this because
The index numbers do not have to be sequential, you can have any index number (from 0 to 32767) for a control in the array.

So if you have three text boxes all called txtField that you have indexed with 1, 10 and 11, the above code will cause an error because it will step from 1 (Me.txtField.LBound) to 2 and there is no control with an index of 2.

You get around this by looping through your control array using the For ... Each construct. This way, if there are gaps in your indexes, you won't get an error. (If you add controls later, the for ... each will still step through in index number order, not the order in which controls were added, whew!)
The following code will not error:

Dim txtRef As TextBox

For Each txtRef In Me.txtField
' Colour the background of each 'Field' text box
txtRef.BackColor = vbRed
Next lngIndex


Why use Control Arrays?
Glad you asked?

Imagine, being the exceptional programmer that you are, that you want to implement that neat feature seen often in windows of automatically selecting the text in a textbox when a user tabs to or clicks on the text box. This is easily achieved in the GotFocus event seen below. The issue can be, if you have a form with 23 textboxes (say a customer edit) you have to put the code (or at least a reference to a global function that runs the code) in the GotFocus event of every individual textbox (23 times).
If instead you have used a control array of 23 texboxes all named txtField then this is a cinch as all the gotfocus events are handled in the one event.
Private Sub txtField_GotFocus(Index As Integer)
With Me.txtField(Index)
.SelStart = 0
.SelLength = Len(.Text)
End With
End Sub

Not only have you cut your coding down, but you maintain integrity as you know all the textboxes are calling the same code. If you add another text box on the form 2 months down the track. The handling of the GotFocus is done as a matter of course (and you don't have customers whinging how one box doesn't work like the others!)

OK, but why have indexes that aren't in sequence?
Ha, glad you asked. (My you are the astute one!)

Ok, now think of the problems with having only one event handler for each event of the text boxes. Say four of the text boxes held phone numbers and you want to make sure that only numbers and brakets are entered.
(OK, you could use a masked edit box, but for the example lets stick with simple text boxes.)

Here is where the power of enums come into play. You can assign a certain range of indexes for phone number containing text boxes and so perform certain actions on them. If you add another phone type text box later on, you only need number it accordingly and all the code is handled for you.
E.g. Here is an example of the text being filtered for phone type boxes using an enum declared at the top of the form's code. You can use any nameing convention.
Option Explicit

' Enum used to identify what data is in each text box
'----------------------------------------------------
Private Enum FieldIndexEnum
fiIDXFirst_General = 1 ' The first index for general details
fiFName = 1
fiLName = 2
fiTitle = 3
fiIDXLast_General = 3 ' The last index for general details

fiIDXFirst_Phone = 100 ' The first index for phone type details
fiPhoneHome = 100
fiPhoneMobile = 101
fiPhoneFax = 102
fiIDXLast_Phone = 102 ' The last index for phone type details

fiIDXFirst_Address = 200 ' The first index for Address details
fiAddrStreet = 200
fiAddrExtra = 201
fiAddrCity = 202
fiAddrPCode = 203
fiIDXLast_Address= 203 ' The last index for Address details
End Enum



Private Sub txtField_GotFocus(Index As Integer)
With Me.txtField(Index)
.SelStart = 0
.SelLength = Len(.Text)
End With
End Sub


Private Sub txtField_KeyPress(Index As Integer, KeyAscii As Integer)

' Format textboxes according to their assigned category
'------------------------------------------------------
Select Case Index

Case fiIDXFirst_Phone To fiIDXLast_Phone
' format the phone textbox by checking what key has been pressed
Select Case UCase$(Chr$(KeyAscii))
Case "A" To "Z", "(", ")"
' Pass

Case vbKeyBack, vbKeySpace
' Let backspace and space through

Case Else
' Not allowed
KeyAscii = 0
End Select


Case fiAddrPCode ' We can also check individual text boxes
Select Case KeyAscii
Case vbKeyBack, vbKeySpace
' Let backspace and space through

Case vbKey0 To vbKey9
' Post code must be numeric

Case Else
KeyAscii = 0
End Select

End Select
End Sub

If you wanted to colour the background of all address boxes yellow, you can do it easily by looping through the textbox array using the fiIDXFirst_Address to fiIDXLast_General indexes.

Hope this gives you some ideas.
HTH
Karimahta


I once had an itch that I scratched and off fell my leg.

EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum