When creating a test program that utilizes many controls, often it is desirable to query or manipulate those controls in a controlled sequence, such as a For/Next loop. An example of this might be a group of eight Switch controls representing the value of a binary byte (figure 1). In these instances it is necessary to create an array of control objects that can be referenced using the loop count variable.
Figure 1 - Using switches to enter or display binary values in a program
The typical method for accessing a control is to reference the control by it’s name. If, for example, you created a Switch control, and named that switch object swMySwitch, then to print the switch position (Value) for swMySwitch you would use the following:
Print swMySwitch.Value
But if, as in the example in figure 1, you had eight switches, or 16 or 32, then you would need to reference each switch specifically by its unique name in order to print the switch position:
Print swMySwitch0.Value Print swMySwitch1.Value Print swMySwitch2.Value Print swMySwitch3.Value Print swMySwitch4.Value Print swMySwitch5.Value Print swMySwitch6.Value Print swMySwitch7.Value
A much simpler approach would be to print the switch positions using a For/Next loop:
For index=0 to 7 Print objMySwitch[index].Value ! Reference switch by array index number Next
To use an array of control objects, first you must define a variable array to store the objects in. The array variable must be of a Control Object type - refer to the ATEasy Help for a comprehensive list of the standard control types. You can use the generic AControl type object, or you can use the specific control object, like ASwitch:
objMyGeneric: AControl[8] objMySwitch: ASwitch[8]
The advantage of using the specific control type, like ASwitch, is that all of the properties and methods associated with the control are available using ATEasy's code completion tools. This is because the ASwitch object uses Early Binding, which exposes all of the properties of an object at design time. The generic AControl or Object object uses Late Binding and does not display all of the properties of all controls. Late binding exposes the object to the application at run time, so the properties of the object are not known to the application at design time. For example, the Value property of an ASwitch control can be accessed via a dropdown list with a variable of type ASwitch, but not with a variable of type AControl. The Value property can still be referrenced within a program for a generic type control, assuming it is valid for the control object stored in the AControl variable, but you must type the property manually in your program code.
The advantage of using the generic AControl object is that any control type can be assigned to it in a "mix-n-Match" process. Since not all controls represented in mix-n-match grouping will share the same properties, you can use the ATEasy Try/Catch statement to test for non-existant controls or properties and avoid ATEasy run-time errors. Refer to the ATEasy help for information regarding Early and Late binding objects. The remaining examples in the article will use control objects with Early Binding.
Once an appropriate array variable has been defined, then you must copy the control object to the array. There are two methods for doing this. The first is to reference the object by it's name, the second is to use the object's Tab Order. The first method is shown in the code segment below. An array of type ASwitch is created with 8 elements, then each of the eight ASwitch objects are copied to the array in ascending order:
aobjSwitch: ASwitch[8]
aobjSwitch[0]=swMySwitch0 aobjSwitch[1]=swMySwitch1 aobjSwitch[2]=swMySwitch2 aobjSwitch[3]=swMySwitch3 aobjSwitch[4]=swMySwitch4 aobjSwitch[5]=swMySwitch5 aobjSwitch[6]=swMySwitch6 aobjSwitch[7]=swMySwitch7
This is an inefficient process for placing control objects into an array by name. Fortunately, the Controls() statement provides a much simpler process for referencing an object either by it's unique text name (shown below), or by its Tab Order (discussed later):
i: Long aobjSwitch: ASwitch[8]
For i=0 to 7 aobjSwitch[i]=Controls("swMySwitch"+Str(i)) ! Reference control by text name Next
The tab order is the order in which a user moves from one control to another in an application when pressing the TAB key. Each form has its own tab order, and some controls, such as the GroupBox, has its own tab suborder. Usually, the tab order is the same as the order in which you created the controls within an ATEasy form, or within an ATEasy control. However, the tab order can be redefined at anytime using the TabOrder button. Refer to the ATEasy online help for additional information about Tab Orders.
By clicking on the TabOrder button while the form containing the eight switches from figure 1 is active, you can see the current tab order for the switches (figure 2). The order was defined as the controls were created, with the switch on the right representing the LSB and tab order 0. The MSB is tab order 7, and the label with the text "Byte Value" is tab order 8. The tab order can be redefined simply by clicking on the controls in whatever tab order you desire.
Figure 2 - Tab ordering of controls on a form
By utilizing the Controls statement you can take advantage of the tab order to simplify the process of assigning control objects to an array. The Controls statement returns a control object as specified by a given control name or index. The index value is the tab order, so the eight switch control objects can be stored in the aobjSwitch[] array using the simple For/Loop structure shown below:
i: Long aobjSwitch: ASwitch[8]
For i=0 to 7 aobjSwitch[i] = Controls(i) ! Reference control by tab order Next
Once the switch objects are stored to the control array, the controls can be used by referencing the array and index, the same as if you used the control directly. For example, if you wanted to calculate the byte value represented by the switch positions, the following procedure could be used:
i: Long lByteValue: Long=0
For i=0 to 7 lByteValue=lByteValue+((2^i)*aobjSwitch[i].Value) Next lblValue.Caption=Str(lByteValue)
Figure 3 - Byte value represented by switch positions
As mentioned previously in this article, some ATEasy controls allow embedding other controls within them. The AGroupBox is an example of this type of control. In this case, the tab order for controls embedded within another control have a sub-index number, or an indented tab order. If you were to place the eight byte-value switches inside a AGroupBox control, the AGroupBox control would have the major tab order, or index value, and each of the switches would have a sub tab order. Assuming the GroupBox control had a tab order of 0, then the switche controls inside the AGroupBox would have a tab order of 0.0, 0.1, 0.2 and so on, up to tab order 0.7, and the Byte Value label which had been tab order 8 is now tab order 1 (figure 3).
Figure 4 - Tab ordering of controls within controls
A new reference level is added for accessing the switch control objects. Since they are now embedded in the AGroupBox, you must reference the AGroupBox control first, before having access to the switch controls within it. This is done by adding another level of the Controls property to reference the GroupBox. The code below demonstrates how to build the array of ASwitch objects from switches embedded in a AGroupBox:
i: Long aobjSwitch: ASwitch[8]
For i=0 to 7 aobjSwitch[i] = Controls(0).Controls(i) Next
Refer to Knowledgebase article Q200169 for an example of how to create controls dynamically on an ATEasy form.
|
Keywords
|
ATEasy, array, control, object array, control array, tab order, group box, object.InsertControl(), Insert Control, AddHandler
|