Wednesday, November 4, 2009

Control Arrays

So far, we've dealt with individual controls, each one with a distinctive name and a distinct set of properties and events. In addition to these, Visual Basic embodies the concept of control arrays, in which multiple controls share the same set of event procedures even though each individual element in the array can have different values for its properties. A control array can be created only at design time, and at the very minimum at least one control must belong to it. You create a control array following one of these three methods:

  • You create a control and then assign a numeric, non-negative value to its Index property; you have thus created a control array with just one element.
  • You create two controls of the same class and assign them an identical Name property. Visual Basic shows a dialog box warning you that there's already a control with that name and asks whether you want to create a control array. Click on the Yes button.
  • You select a control on the form, press Ctrl+C to copy it to the clipboard, and then press Ctrl+V to paste a new instance of the control, which has the same Name property as the original one. Visual Basic shows the warning mentioned in the previous bullet.

Control arrays are one of the most interesting features of the Visual Basic environment, and they add a lot of flexibility to your programs:

  • Controls that belong to the same control array share the same set of event procedures; this often dramatically reduces the amount of code you have to write to respond to a user's actions.
  • You can dynamically add new elements to a control array at run time; in other words, you can effectively create new controls that didn't exist at design time.
  • Elements of control arrays consume fewer resources than regular controls and tend to produce smaller executables. Besides, Visual Basic forms can host up to 256 different control names, but a control array counts as one against this number. In other words, control arrays let you effectively overcome this limit.

The importance of using control arrays as a means of dynamically creating new controls at run time is somewhat reduced in Visual Basic 6, which has introduced a new and more powerful capability. Read about dynamic control creation in Chapter 9.

Don't let the term array lead you to think control array is related to VBA arrays; they're completely different objects. Control arrays can only be one-dimensional. They don't need to be dimensioned: Each control you add automatically extends the array. The Index property identifies the position of each control in the control array it belongs to, but it's possible for a control array to have holes in the index sequence. The lowest possible value for the Index property is 0. You reference a control belonging to a control array as you would reference a standard array item:

Text1(0).Text = ""

Sharing Event Procedures

Event procedures related to items in a control array are easily recognizable because they have an extra Index parameter, which precedes all other parameters. This extra parameter receives the index of the element that's raising the event, as you can see in this example:

Private Sub Text1_KeyPress(Index As Integer, KeyAscii As Integer)
MsgBox "A key has been pressed on Text1(" & Index & ") control"
End Sub

The fact that multiple controls can share the same set of event procedures is often in itself a good reason to create a control array. For example, say that you want to change the background color of each of your TextBox controls to yellow when it receives the input focus and restore its background color to white when the user clicks on another field:

Private Sub Text1_GotFocus(Index As Integer)
Text1(Index).BackColor = vbYellow
End Sub
Private Sub Text1_LostFocus(Index As Integer)
Text1(Index).BackColor = vbWhite
End Sub

Control arrays are especially useful with groups of OptionButton controls because you can remember which element in the group has been activated by adding one line of code to their shared Click event. This saves code when the program needs to determine which button is the active one:

' A module-level variable
Dim optFrequencyIndex As Integer

Private Sub optFrequency_Click(Index As Integer)
' Remember the last button selected.
optFrequencyIndex = Index
End Sub

Creating Controls at Run Time

Once you have created a control array at design time, even with just one item, it's straightforward to create new items at run time using the Load command:

' Suppose you created Text(0) at design time.
Load Text1(1)
' Move the new control where you need it, and resize it.
Text1(1).Move 1200, 2000, 800, 350
' Set other properties as required.
Text1(1).MaxLength = 10
...
' Finally make it visible.
Text1(1).Visible = True

The Load command creates the new control with exactly the same set of properties that the first item of the array—Text1(0) in the preceding example—had at design time, including the position on the form. The only exception to this rule is that the Visible property for a control created in this way is always False because Visual Basic correctly expects that you want to move the new control to a different position before making it visible. Once you have dynamically added a control, it belongs to the control array and can be treated exactly like those controls created at design time.

You can remove controls from a control array using the Unload command, as in the following line of code:

Unload Text1(1)

You can unload only controls that were added dynamically at run time; if you use the Unload command on an item of the array that had been created at design time, an error occurs. If you unload an item and then reload an item with the same index, you're actually creating a brand-new instance, which inherits its properties, size, and position from the first element in the array, as I explained previously.

Iterating on the Items of a Control Array

Control arrays often let you save many lines of code because you can execute the same statement, or group of statements, for every control in the array without having to duplicate the code for each distinct control. For example, you can clear the contents of all the items in an array of TextBox controls as follows:

For i = txtFields.LBound To txtFields.UBound
txtFields(i).Text = ""
Next

Here you're using the LBound and UBound methods exposed by the control array object, which is an intermediate object used by Visual Basic to gather all the controls in the array. In general, you shouldn't use this approach to iterate over all the items in the array because if the array has holes in the Index sequence an error will be raised. A better way to loop over all the items of a control array is using the For Each statement:

Dim txt As TextBox
For Each txt In txtFields
txt.Text = ""
Next

A third method exposed by the control array object, Count, returns the number of elements it contains. It can be useful on several occasions (for example, when removing all the controls that were added dynamically at run time):

' This code assumes that txtField(0) is the only control that was
' created at design time (you can't unload it at run time).
Do While txtFields.Count > 1
Unload txtFields(txtFields.UBound)
Loop

Arrays of Menu Items

Control arrays are especially useful with menus because arrays offer a solution to the proliferation of menu Click events and, above all, permit you to create new menus at run time. An array of menu controls is conceptually similar to a regular control array, only you set the Index property to a numeric (non-negative) value in the Menu Editor instead of in the Properties window.

There are some limitations, though: All the items in an array of menu controls must be adjacent and must belong to the same menu level, and their Index properties must be in ascending order (even though holes in the sequence are allowed). This set of requirements severely hinders your ability to create new menu items at run time. In fact, you can create new menu items in well-defined positions of your menu hierarchy—namely, where you put a menu item with a nonzero Index value—but you can't create new submenus or new top-level menus.

Now that you have a thorough understanding of how Visual Basic's forms and controls work, you're ready to dive into the subtleties of the Visual Basic for Applications (VBA) language. The next chapter is devoted to the many data types you can use in your programs.

No comments:

Post a Comment