In Visual Basic, you can create arrays of any data type you want. You can also create an array of controls. Control arrays are a distinctive feature of Visual Basic that brings efficiency and power to the language. You can use them to create a common event procedure that's shared among all the controls in the control array. You also can use them to add and remove controls and forms to your program dynamically at runtime. This chapter shows you all you need to know to be able to work effectively with them.
Can I create a control array?The name Index is used for other purposes, so check the online help before assuming that a control can be added to a control array.
All the intrinsic controls can be used in control arrays. These controls all have an Index property that's used to identify a particular control in a control array.
Many control arrays that you create will be built at design time. As you add controls to your form, you will need to group some of them into control arrays. This example shows you how to do that.
Create a control array of CommandButtons
Now that the control array is created, if you go to the Properties window and display the Object drop-down list, notice that there are now two CommandButtons with the name cmdMyButton, each with its own subscript (see Figure 22.1).
FIGURE 22.1 When a control is part of a control array, you must always reference the subscript to access the control.
Double-click either CommandButton to look at the Click event procedure. Notice that it now has an Index argument (see Figure 22.2). This argument is an Integer that indicates the subscript of the control to which the event procedure applies. Because all controls of a control array share the same event procedure, you differentiate between controls by the value of Index--0 is the first control, 1 is the second control, 2 is the third, and so on.
FIGURE 22.2 The Index argument is filled by Visual Basic whenever an event occurs for a control in a control array.
The code in Listing 22.1 displays a string in the titlebar of the form frmMain that reports which CommandButton of the control array cmdMyButton() the user clicked. Copying this code to the cmdMyButton_Click(Index as Integer) event procedure can give you a sense of how to work with the Index argument. Figure 22.3 shows this code in action.
01 Private Sub cmdMyButton_Click(Index As Integer)
02 ` Change the form's caption to indicate which
03 ` button in the control array generated an event.
04 Me.Caption = "You clicked button #" & Index & "."
05 End Sub
LISTING 22.1 Refers to the form in which this code resides
FIGURE 22.3 After the user clicks the button on the right, the form's title changes accordingly.
Making a control array at design time will suffice if you know how many controls you will need in the array. But what do you do if you don't know how many controls you will need in your control array until the program is running? You solve this problem by adding controls to your control array at runtime by using the Load statement.
Add a control to a control array at runtime
Creating a control arrayThis action creates a control array with one element. The Index must be set to zero initially, so that controls loaded later will be added to the control array correctly.
01 Private Sub Form_Load()
02 `Create a new command button
03 Load cmdCtrlArray(1)
04
05 `Move it directly underneath the old one
06 cmdCtrlArray(1).Left = cmdCtrlArray(0).Left
07 cmdCtrlArray(1).Top = cmdCtrlArray(0).Top _
+ cmdCtrlArray(0).Height
08 cmdCtrlArray(1).Caption = "Button #1"
09
10 `Make the new button visible
11 cmdCtrlArray(1).Visible = True
12
13 End Sub
When you run the code, notice that the program makes a new CommandButton on the form and places it just below the first (see Figure 22.4).
FIGURE 22.4 Using the Load statement creates another CommandButton on the form. The rest of the code takes care of positioning the control correctly.
Where did the control go?All newly created elements of a control array have a Visible value of False. When you make your new controls at runtime, don't forget to put a line of code in that sets the value of the Visible property to True. Otherwise, you can't see the control.
You must do a certain amount of tweaking to get a newly created control to be operational in your program. New controls are exact duplicates of the first control element of the control array. The values of all properties except Index and Visible are identical--including the values of Left and Top. Thus, when you create a new control, it will be placed right over the first control in the array. For the new control to be able to coexist with other controls in the control array, you must move the control to a new position.
As you saw in the preceding example, one benefit of control arrays is the ability to have a common event handler. This section features a program that allows users to input some numbers into a numeric telephone touch pad to place a call. Users also can set whether the call should be made by pulse or tone and can choose to send a fax or a simple voice call.
Don't worry if you don't know anything about telephony programming--you won't be writing any. This example is simply designed to show how control arrays could be used in this application.
This program uses a control array of CommandButtons to handle user input. Each keypad button is part of the cmdNum control array. Using a control array greatly simplifies matters. In this project, if you didn't use a control array, you would have 12 event procedures to program--not a very pleasant undertaking. However, when you use a control array, you have only one event procedure to program. You use the Index argument within the control array's one event procedure to figure out which control fired the event procedure (see Figure 22.5).
Listing 22.3 shows the code for the Click() event procedure of the control array. Notice that the control array's event procedure uses a Select Case statement to provide different responses depending on which button has been clicked.
01 Private Sub cmdNum_Click(Index As Integer)
02 Dim strChar As String
03
04 `Find out which button was clicked by analyzing
05 the Index argument. Depending on which button
06 `you push, set the other string variable accordingly.
07 Select Case Index
08 `This button has the "*" character
09 Case 10
10 strChar = "*"
11 `This button has the "#" character
12 Case 11
13 strChar = "#"
14 `All the buttons have captions that match
15 `their index value.
16 Case Else
17 strChar = CStr(Index)
18 End Select
19
20 ` Add the new digit to the phone number.
21 lblNumber.Caption = lblNumber.Caption & strChar
22
23 End Sub
FIGURE 22.5 Every element of a control array is listed in the Properties window with its subscript.
The only issue with this code is that each CommandButton's Index property must match exactly with its Caption property. For instance, this code assumes that the button marked as the one digit has a control array index of 1, the two button has an index of 2, and so on. If these buttons were deleted and re-created, they would have to be put back in order exactly or the code wouldn't work.
Listing 22.4 shows a revised version of this code, which still uses a single event handler but doesn't rely on the value of Index. Instead, it simply uses the value of the Caption property. It's also quite a bit shorter and more reliable.
01 Private Sub cmdNum_Click(Index As Integer)
02 lblNumber.Caption = lblNumber.Caption _
& cmdNum(Index).Caption
03 End Sub
In earlier chapters, you learned that within a group of OptionButtons, only one OptionButton can have a value of True (see Figure 22.6). But as you saw in the dialer application in the last section, sometimes you need to have sets of OptionButtons so that you can return many different sets of choices.
FIGURE 22.6 If you don't group your OptionButtons in containers, they all work as one big group.
Frames aren't the only containersPictureBox controls can also be used as containers, as can the 3D Panel control.
You group OptionButtons by using a container control such as a frame. After a set of OptionButtons is pasted into a frame, the members of the set are exclusive to one another.
You add a Frame control to a form as you would any other control. After a control is pasted into a frame, the frame becomes that control's container. Thus, all coordinates of the child controls are relative to the frame. When you move a frame, all the controls within the frame move with it.
There's a trick to adding controls to the Frame control.
Add a control to a frame
Before you add or paste a control into a frame, make sure that the frame is selected. If you don't have the frame selected, the control is really not being added to the frame. Also, after a control is added or pasted into a frame, it can't be moved out of the frame except by pressing Delete or choosing Cut from the Edit menu. (See Figure 22.7.)
FIGURE 22.7 Make sure that the frame is selected before you add controls to it.
The standard scroll bar controls, HScrollBar and VScrollBar, allow you to move through data or a range of values by clicking the up and down scroll arrows or by moving the scrollbar's scroll box (the little button between the scroll arrows). The scroll bar controls have a few special properties that you should know about, as described in Table 22.1.
Property | Description |
Min | Sets the lowest possible value of the control when the scroll box is positioned at the topmost or leftmost of the respective scroll bar. The default value is 0, but negative numbers can also be used. |
Max | Sets the highest possible value of the control when the scroll box is at the bottommost or rightmost of the respective scroll bar. The default value is 32,767. |
Value | The position of the scroll box relative to the Max and Min properties. |
LargeChange | Sets the amount of change of the Value property when users click between the scroll box and scroll arrow. |
SmallChange | Sets the amount of change of the Value property when users click the scroll arrow. |
Make a form with VScrollBar and HScrollBar controls
Property | Setting |
Min | 0 |
Max | 20 |
SmallChange | 1 |
LargeChange | 2 |
FIGURE 22.8 The only difference between the HScrollBar and VScrollBar controls is their orientation.
Private Sub hscrWE_Change() txtWE.Text = CStr(hscrWE.Value) End Sub Private Sub vscrNS_Change() txtNS.Text = CStr(vscrNS.Value)End Sub
When you run the code, notice that when you click the scroll arrows of the HScrollBar or VScrollBar control, the value of the respective TextBox changes by 1, the value of the SmallChange property. If you click the area between the scroll box and the scroll arrow, the amount in the TextBox changes by 2, the value of the LargeChange property (see Figure 22.9).
FIGURE 22.9 Because the Max property is set to 20, when you move the scroll bars, the values shown in the TextBoxes will never exceed 20.
Using For...Next loops is an efficient way to traverse and manipulate elements in a control array. Listings 22.5 and 22.6 show you two ways to create and manipulate elements in a control array. Listing 22.5 illustrates the old-fashioned way--creating the controls one at a time by using the Load statement. Listing 22.6 shows you a way to make the controls by using a For...Next loop. Compare the two.
01 Private Sub cmdMakeArray_Click()
02 `Create additional controls in the
03 `imgFace control array.
04 Load imgFace(1)
05 Load imgFace(2)
06 Load imgFace(3)
07 Load imgFace(4)
08
09 `Set the top new elements of the control array
10 `to the top of the one before it.
11 imgFace(1).Top = imgFace(0).Top
12 imgFace(2).Top = imgFace(1).Top
13 imgFace(3).Top = imgFace(2).Top
14 imgFace(4).Top = imgFace(3).Top
15
16 `Set the left starting position of the new
17 `control to the left plus the width of the control
18 `before it
19 imgFace(1).Left = imgFace(0).Left + imgFace(0).Width
20 imgFace(2).Left = imgFace(1).Left + imgFace(1).Width
21 imgFace(3).Left = imgFace(2).Left + imgFace(2).Width
22 imgFace(4).Left = imgFace(3).Left + imgFace(3).Width
23
24 `Set ALL of the controls in the control array
25 `and make them visible
26 imgFace(0).Visible = True
27 imgFace(1).Visible = True
28 imgFace(2).Visible = True
29 imgFace(3).Visible = True
30 imgFace(4).Visible = True
31 End Sub
01 Private Sub cmdLoopArray_Click()
02 Dim i As Integer `Counter variable
03
04 `Set the picture of the first element of the
05 `imgFace control array to the picture in the control,
06 `imgHappy face.
07 imgFace(0).Picture = imgHappy.Picture
08
09 For i = 1 To 4
10 `Create a new control in the array
11 Load imgFace(i)
12 `Set the top of the new control to top of the
13 `one before it.
14 imgFace(i).Top = imgFace(i - 1).Top
15 `Set the left starting position of the new
16 `control to the left plus the width of the control
17 `before it
18 imgFace(i).Left = imgFace(i - 1).Left _
+ imgFace(i - 1).Width
19 imgFace(i).Visible = True
20 Next i
21
22 End Sub
As you compare the two, notice that everything you can do one at a time, with regard to control array elements, you can do with much more elegance by using a For...Next loop. For...Next loops can also control an unknown number of elements in any control array, giving you versatility and extensibility.
Figure 22.12 shows the results of the application. The upper portion of the project's form shows an implementation of the code in Listings 22.5 and 22.6. The bottom portion of the form shows a way to use the VScrollBar control to dynamically generate a varying number of controls in a control array of ImageBoxes.
FIGURE 22.10 The number of controls shown will be one more than the scroll position because the zero element is the first element in the control array.
Don't try this at home... or workIn a real-world production environment, unloading and re-creating control array elements each time you need them is a grossly inefficient programming practice. It's done here to demonstrate this Visual Basic feature.
When you closely study the code in Listing 22.7 (the Change event procedure for one of the VScrollBar controls), notice that not only does the code dynamically create new elements of the ImageBox control array through the Load statement, but it also dynamically destroys all but the zero value element of the control array through the Unload statement.
01 Private Sub vscrFirst_Change()
02 `This sub removes all the existing elements of
03 `the control array, imgFirst(), except for the
04 `first one, and then creates a new set of elements
05 `as determined by the value of the vertical scrollbar
06 `position.
07
08 `Number of images in
09 `ImageBox Control array
10 Static intNumOfImage As Integer
11 Dim i As Integer `Counter variable
12
13 `Report the value of the scrollbar position
14 `in a TextBox. Don't forget to convert to an integer.
15 txtFirst.Text = CStr(vscrFirst.Value)
16
17 `Set the Picture property of the first element of
18 `the ImageBox control array to the picture in the
19 `happy face image box.
20 imgFirst(0).Picture = imgHappy.Picture
21
22 `Unload all pre-existing elements of the ImageBox
23 `control array.
24
25 `Make sure the previous value of the Static variable
26 `is greater than zero. If the value is zero, you would
27 `be trying to the zero element control array element.
28 `This is bad!
29 If intNumOfImage > 0 Then
30 `If the number is over zero, there are elements left
31 `over from your last time uses of this event
32 `procedure.
33
34 `(Remember, a the value of a Static variable holds
35 `value after the event procedure goes out of scope.)
36 For i = 1 To intNumOfImage
37 `Nuke all the elements of the control array
38 Unload imgFirst(i)
39 Next i
40 End If
41
42 `Set a new value for the static variable, intNumOfImage
43 `based upon the value of the scroll bar position.
44 intNumOfImage = vscrFirst.Value
45
46 `Traverse the intended number of new controls for the
47 `control array.
48 For i = 1 To intNumOfImage
49 `Make a new ImageBox for the control array
50 Load imgFirst(i)
51 `Set the top of the new control to top of the
52 `one before it.
53 imgFirst(i).Top = imgFirst(i - 1).Top
54 `Set the left starting position of the new
55 `control to the left plus the width of the control
56 `before it
57 imgFirst(i).Left = imgFirst(i - 1).Left _
+ imgFirst(i - 1).Width
58 Next i
59
60 `Traverse ALL of the controls in the control array
61 `and make them visible
62 For i = 0 To intNumOfImage
63 imgFirst(i).Visible = True
64 Next i
65 End Sub
One note about this application: If you try to Load a control in a control array by using a subscript for an already loaded control, you will get an error. If you click the Make Control Array the Hard Way button and then click the Make Control Array Using Loops button, an error will be generated (see Figure 22.11). This is because the first button's Click event procedure creates a control array, and the second button's Click event procedure tries to re-create the same control array by using the same subscripts. Be careful when you work with control arrays and For...Next loops.
FIGURE 22.11 Using a Load statement on an array element that already exists will cause an error.
© Copyright, Macmillan Computer Publishing. All rights reserved.