Controls are the primary medium of user interaction. By typing and clicking, and by moving through controls on the forms in your application, users can manipulate their data and accomplish the tasks they want to do. This chapter discusses:
•
Understanding Controls and Data•
Choosing the Right Control for the Task•
Making Controls Easier to Use•
Extending FormsUnderstanding Controls and Data
You can have two types of controls on your forms: controls that are bound to data and controls that are not. When users interact with bound controls, the values that they enter or choose are stored in the data source, which can be a table field, a cursor field, or a variable. You bind a control to data by setting its
ControlSource property, or, in the case of grids, its RecordSource property.
If you don’t set the ControlSource property of a control, the value that the user enters or chooses in the control is only stored as a property setting. The value is not written to disk or stored in memory beyond the lifetime of the control.
Effect of a ControlSource Property Setting on Controls
Control
Effect
Check box
If the ControlSource is a field in a table, then NULL values, logical values true
(.T.) or false (.F.), or numeric values 0, 1, or 2 in the ControlSource field cause
the check box to be selected, cleared, or grayed as the record pointer moves
through the table.
Column
If the ControlSource is a table field, the user is directly editing the field when
editing values in the column. To bind an entire grid to data, set the
RecordSource property of the grid.
List box or combo box
If the ControlSource is a variable, the value the user chooses in the list is stored
in the variable. If the ControlSource is a field in a table, the value is stored in
the field at the record pointer. If an item in the list matches the value of the
field in the table, the item is selected in the list when the record pointer moves
through the table.
Option button
If the ControlSource is a numeric field, 0 or 1 is written to the field, depending
on whether the button is chosen.
If the ControlSource is logical, .T. or .F. is written to the field, depending on
whether the button is chosen. If the record pointer moves in the table, the value
of the option button is updated to reflect the new value in the field.
If the ControlSource of the option button’s OptionGroup control (not the option
button itself) is a character field, the caption of the option button is stored to the
field if the option button is chosen. Note that the control source for an option
button (as distinct from an OptionGroup control) cannot be a character field, or
Visual FoxPro will report a data type mismatch when the form is run.
Spinner
The spinner reflects and writes numeric values to the underlying field or
variable.
Text box or edit box
The value in the table field is displayed in the text box. Changes the user makes
to this value are written back to the table. Moving the record pointer affects the
Value property of the text box.
Some of the tasks you want to accomplish with controls require having data bound to the control. Other tasks will not.
Choosing the Right Control for the Task
Visual FoxPro controls are flexible and versatile. Though there are multiple controls you could use to accomplish any particular task, you need to have a consistent approach to the controls you use so that users can tell what to expect when they see the interface you provide. For example, a label has a Click event in the same way that a command button does, but users familiar with graphical interfaces expect to click on command buttons to perform actions.
Most of the functionality you’ll want to build into your forms will fall under one of the following categories:
•
Providing users with a set of predetermined choices•
Accepting user input that can’t be predetermined•
Accepting user input in a given range•
Allowing users to perform specific actions•
Performing specific actions at given intervals•
Displaying informationProviding a Set of Predetermined Choices
One of the most straightforward ways to ensure the validity of the data in a database is to give users a predetermined set of options. By controlling user choices, you can make sure that no invalid data is stored in the database. The following controls allow you to provide users with a set of predetermined choices:
•
Option button groups•
List boxes and drop-down lists•
Check boxesUsing Option Button Groups
Option button groups are containers that contain option buttons. Typically, option buttons allow users to specify one of a number of operational options in a dialog box rather than data entry. For example, option buttons can be used to specify output to a file, a printer, or to print preview .
Setting the Number of Option Buttons in an Option Button Group
When you create an option button group on a form, two option buttons are included by default. You can determine how many option buttons are in a group by changing the ButtonCount property.
To set the number of option buttons in a group
•
Set the ButtonCount property to the desired number of option buttons.For example, to have a group of six option buttons, set the ButtonCount property of the option button group to 6.
The Value property of the group indicates which of the buttons has been chosen. For example, if a user chooses the fourth option button in a group of six option buttons, the value of the option button group is 4. If the group’s ControlSource property is a character field, or if the Value property is set to a character value before the form is run, the group’s Value property is the caption of the selected option button.
Setting Option Button Properties
To manually adjust individual elements of an option button or command button group in the Form Designer, choose Edit from the group’s shortcut menu.
You can set properties on individual buttons in the Properties window. You can also set these properties at run time by specifying the name of the option button and the desired property setting. For example, the
following line of code, included in the method or event code of some object on the same form as the option button group, sets the caption of
optCust in the option button group opgChoices:
THISFORM.opgChoices.optCust.Caption = "Sort by Customer"
You can also set these properties at run time by using the Buttons property and specifying the index number of the option button in the group. For example, if
optCust is the third button in the group, the following
line of code also sets the caption of optCust:
THISFORM.opgChoices.Buttons(3).Caption = "Sort by Customer"
To set properties on all buttons in a group
•
Use the SetAll method of the group.For example, the following line of code disables all the buttons in an option button group named
opgMyGroup on a form:
THISFORM.opgMyGroup.SetAll("Enabled",.F., "OptionButton")
Enabling and Disabling Buttons in a Group
The previous example shows how to programmatically disable all option buttons in a group. When the buttons are disabled, they are displayed in the colors specified in the DisabledForeColor and
DisabledBackColor properties of the option buttons. You could also set the Enabled property of the option button group to false (.F.) to disable the group; however, there would be no visual clue for the user.
Determining Which Option Button Is Currently Selected
You can use the Value property of the option button group to determine which option button in the group is selected. If the control source for the button is numeric, you have five option buttons in a group. If the third button is selected, the Value property of the option button group is 3; if no option buttons are selected, the Value property of the option button group is 0.
You can also determine the caption of the selected option button by using the Value and Buttons properties of the group. For example, the following line of code stores the Caption property of the selected option button to a variable
cSelected.
oGroup = THISFORM.opg1
cSelected = oGroup.Buttons(oGroup.Value).Caption
Using Option Buttons to Store User Choices to a Table
While it is not as common, you can use option buttons to get information from a user to be stored in a table by saving the Caption property. If you have a standardized testing application, for example, you could use option buttons to allow a user to choose among multiple choice options A, B, C, or D. You could also use option buttons to indicate gender in an employee table.
To store the Caption property of an option button to a table
1
Set the Value property of the option button group to an empty string.
2
Set the ControlSource property of the option button group to a character field in a table.
For example, if the captions of the option buttons in a group are “A”, “B”, “C”, and “D”, and the ControlSource of the option button group is a character field, when a user chooses the button with the caption “B”, “B” is stored in the field.
To see an example of a multiple-choice test using option buttons, run SOLUTION.APP in the SAMPLES\SOLUTION, directory and choose “Present a user with multiple choices.”
Using List Boxes and Drop-Down List Boxes
List boxes and drop-down list boxes (combo box controls with the Style property set to 2 - Dropdown List) provide a user with scrollable lists that contain a number of options or pieces of information. In a list box, multiple items can be visible at all times. In a drop-down list box, only one item is visible, but a user can click the down button to display a scrolling list of all the items in the drop-down list box.
Run SOLUTION.APP in the SAMPLES\SOLUTION directory to see several examples that demonstrate using list boxes and drop-down list boxes, including the following:
•
Multiselect items in a list.•
Fill a list with values from different sources.•
Display multiple columns in a list.•
Sort list items.•
Move items between lists.Tip If you have room on the form and if you want to emphasize the choices a user has, use a list. To
conserve space and emphasize the currently selected item, use a drop-down list box.
Common List Properties and Methods
The following list box properties are commonly set at design time.
Property
Description
ColumnCount
The number of columns in the list box.
ControlSource
Where the value that a user chooses from the list is stored.
MoverBars
Whether mover bars are displayed to the left of list items so that a user can easily
rearrange the order of items in the list.
Multiselect
Whether the user can select more than one item in the list at a time.
RowSource
Where the values displayed in the list come from.
RowSourceType
Whether the RowSource is a value, a table, a SQL statement, a query, an array, a
list of files, or a list of fields.
Note The Value property of a list can be numeric or character. The default is numeric. Set the Value
property to an empty string if the RowSource is a character value and if you want the Value property to reflect the character string of the selected item in the list. You can press the SPACEBAR
and then the
BACKSPACE
key to enter an empty string for a property in the Properties window.
The following list box methods are commonly used.Method
Description
AddItem
Adds an item to a list with a RowSourceType of 0.
RemoveItem
Removes an item from a list with a RowSourceType of 0.
Requery
Updates the list if the values in the RowSource have changed.
Filling a List Box or a Combo Box
You can fill a list box with items from a variety of sources by setting the RowSourceType and RowSource properties.
Choosing the Type of Data for a List or Combo Box
The RowSourceType property determines what kind of source populates the list box or combo box — for example, an array or a table. Once you have set the RowSourceType, specify the source of the list items by setting the RowSource property.
RowSourceType
Source of the List Items
0
None. Programmatically add items to the list.
1
Value
2Alias
3SQL Statement
4Query (.QPR)
5Array
6Fields
7Files
8Structure
9
Popup. Included for backward compatibility.
The following sections describe the various RowSourceType settings.
None If you set the RowSourceType property to 0, the default, the list is not automatically populated. You
can add items to the list by using the AddItem method:
frmForm1.lstMyList.RowSourceType = 0
frmForm1.lstMyList.AddItem("First Item")
frmForm1.lstMyList.AddItem("Second Item")
frmForm1.lstMyList.AddItem("Third Item")
The RemoveItem method allows you to remove items from the list. For example, the following line of code removes “Second Item” from the list:
frmForm1.lstMyList.RemoveItem(2)
Value If you set the RowSourceType property to 1, you can specify multiple values in the RowSource
property to be displayed in the list. If you set the RowSource property through the Properties window, include a comma-delimited list of items. If you set the RowSource programmatically, include the comma- delimited list in quotation marks:
Form1.lstMyList.RowSourceType = 1
Form1.lstMyList.RowSource = "one,two,three,four"
Alias If you set the RowSourceType property to 2, you can include values from one or more fields in an
open table.
If the ColumnCount property is 0 or 1, the list displays values in the first field of the table. If you set the ColumnCount property to 3, the list displays values in the first three fields of the table. To display fields in a different order than they are stored in the table, set the RowSourceType property to 3 - SQL Statement or 6 - Fields.
Note If the RowSourceType is 2 - Alias or 6 - Fields, when a user chooses a new value in the list, the table
record pointer moves to the record with the value of that item.
SQL Statement If you set the RowSourceType property to 3 - SQL Statement, include a SELECT - SQL
statement in the RowSource property. For example, the following statement selects all fields and all records from the Customer table into a cursor:
SELECT * FROM Customer INTO CURSOR mylist
If you set the RowSource programmatically, remember to enclose the SELECT statement in quotation marks.
Note By default, Visual FoxPro SELECT statements without INTO clauses immediately display the
resulting cursor in a Browse window. Since you rarely want this behavior in a RowSource SQL statement, include an INTO CURSOR clause in your SELECT statement.
Query If you set the RowSourceType property to 4, you can populate your list box with the results of a
query you designed in the Query Designer. When RowSourceType is set to 4, set RowSource to the .QPR file. For example, the following line of code sets the RowSource property of a list to a query.
THISFORM.List1.RowSource = "region.qpr"
If you don’t specify a file extension, Visual FoxPro assumes an extension of .QPR.
Array If you set the RowSourceType property to 5, the list is populated with the items in an array. You can
create an array property of the form or form set for the RowSource or use an array created elsewhere in your application.
For information about creating array properties, see Chapter 9, Creating Forms.
Troubleshooting The RowSource setting of a list is evaluated by Visual FoxPro as needed in your
application, not just in the method in which you set the RowSource. You need to keep this scope in mind. If you create a local array in a method, that array will be scoped to the method and will not be available in all cases when Visual FoxPro needs to evaluate the property setting. If you set the RowSource of a list to an array property of the form or form set, you need to reference the property relative to the list, not relative to the method in which you set the property. For example, if you have a form array property named
THIS.lst1.RowSource = "THIS.arrayprop" && Error
THIS.lst1.RowSource = "THISFORM.arrayprop" && No error.
To populate a list with the elements in a multi-dimensional array
1
Set the RowSourceType property to 5.
2
Set the RowSource property to the multi-dimensional array.
3
Set the ColumnCount property to the number of columns to display.
4
Set the ColumnWidths property to the desired widths for each column.
Fields If you set the RowSourceType property to 6, you can specify a field or comma-delimited list of fields
to populate the list, such as:
contact,company,country
You can include the following types of information in the RowSource property of a list with a RowSourceType of 6 - Fields:
•
field•
alias.field•
alias.field, field, field, ...If you want to have fields from multiple tables in the list, set the RowSourceType property to 3 - SQL Statement.
Unlike a RowSourceType of 2 - Alias, a RowSourceType of 6 - Fields allows you to display fields independent of their actual positions in the table.
Files If you set the RowSourceType property to 7, the list is populated with files in the current directory.
Additionally, options in the list allow you to choose a different drive and directory for file names to be displayed in the list.
Set RowSource to the skeleton of the type of files you want to be displayed in the list. For example, to display Visual FoxPro tables in the list, set the RowSource property to *.dbf.
Structure If you set the RowSourceType property to 8, the list is populated with the fields in the table that
you specify when you set the RowSource property. This RowSourceType setting is useful if you want to present the user with a list of fields to search for values in or a list of fields to order a table by.
Popup If you set the RowSourceType property to 9, you can fill the list from a previously defined popup.
This option is included for backward compatibility.
Creating Multicolumn List Boxes
Although the default number of columns in a list box is one, a list box in Visual FoxPro can contain as many columns as you want. A multicolumn list box differs from a grid in that you select a row at a time in a multicolumn list box while you can select individual cells in a grid, and data in the list cannot be directly edited.
To display multiple columns in a list box
1
Set the ColumnCount property to the number of desired columns.
2
Set the ColumnWidths property. For example, if there are three columns in the list box, the
following command would set the column widths to 10, 15, and 30, respectively:
THISFORM.listbox.ColumnWidths = "10, 15, 30"
3
Set the RowSourceType property to 6 - Fields.
4