Introduction to the Grid Control


This document is reprinted from the Microsoft DevCon 95 Speaker materials and is provided "as-is." This document and any associated demo files were created using Visual FoxPro 3.0. Some features discussed may have changed in Visual FoxPro 5.0.

Meng Phua
Microsoft Corporation

Objectives of the Grid Control

A Grid Control is the tabularization of data that may be presented in a form. Most of the events and properties associated with forms and the controls on the forms may be applied to the grid control (and cells of the grid control) as well. There are at the minimum three levels of containership with respect to a grid control: Grid, Columns, Headers and Controls. The distinctions might be best understood this way: A grid is merely a container column, a column is a vertical group of cells (like data) which may contain other controls.

The grid control amounts to a specialized view of a form. Because of its inherent ability to display many rows at the same time, it is a specialized continuous form. Consequently, the grid control and its associated columns is endowed with many of the same properties and events that are applicable to forms and their controls.

Anatomy of a Grid Control

The building blocks of the Grid Control namely the FoxPro Base Classes: Grid, Column and Header each possess their own set of properties, events and methods. The user can think of the Grid Control as a composite object much like the PageFrame or OptionButton container controls.

There are two levels of containership in the Grid control. A Grid is a container of Columns and a Column is a container consisting of a control/controls and a single Header. By default, the Grid Columns contain a Textbox named Text1, i.e. GridX.ColumnX.Text1. However, the Column container can host any of the numerous FoxPro visual classes, e.g. ComboBoxes, Grids, PageFrames, CheckBoxes, etc.

The number of nested containers within the Grid Column is not artificially limited by the product but rather by the amount of available system resources. For example, we will not prevent the user from nesting n-levels of Grids within Grid Columns.

Use the Columns’ AddObject, CurrentControl, Sparse and Bound properties to add and display controls in Columns. Grid Columns cannot contain Formsets, Forms, Toolbars, DE and OLE Controls

Quick-n-Dirty Grid creation

A quick and dirty way of populating the grid is to:

  1. Add the Table/View used by the Grid Control to the Data Environment.

  2. Define the region of the Grid Control on the Form.

  3. Set the Grid’s RecordSource Property, leave ColumnCount at its default value of -1.

During runtime, the Grid control will automatically populate the Header with the datasource field name and fill the Columns from the Datasource.

Users are also advised to utilize the Grid Builder to first create their Grid control, further adjustments can be made to the Grid Control by using the Form/Class Designer.

Ordering Grid Columns

The ordinal or visual position of a Column in a Grid Control is set through the Column-level ColumnOrder property. The Order property accepts a numeric value which represents the ordinal position of the Column within the Grid control. Users can move a Column to another location in the Grid simply by resetting the Order property. The Order of the other Columns in the Grid will automatically readjust to reflect the move. Subsequently, the Column Moved event will fire on the Column which was reordered.

When Columns are added or removed either in the Form Designer or by the AddObject/RemoveObject/AddColumn/RemoveColumn Methods, the Grid control will automatically reorder the remaining Columns so that there are no ‘gaps’ in the Order and it is always sequential.

The SETALL Method

The user can use the Grid and Column SetAll method to set properties on all Columns or Column Controls. For example, to change the BackColor of all Columns in the Grid to Red

Form1.Grid1.SetAll('BackColor', 'RGB(255, 0, 0)', 'Column')

or to change the Font on all the Headers

Form1.Grid1.Column1.SetAll('FontName', 'Arial', 'Header')
The first parameter is the property to be changed, the second is the new value of the property and the 3rd parameter is the class name which is optional

Collection Vs. Name reference

Columns are by default named Column1-N when the ColumnCount property is set , however this does not prevent the user from giving them more meaningful names. For example:

DEFINE CLASS MyGrid AS GRID
COLUMNCOUNT = 3
COLUMN1.NAME = "Company"
COLUMN2.NAME = "State"
COLUMN3.NAME = "Phone"
ENDDEFINE
Alternatively, we can access these Columns and Headers by Collection. The Columns() property is an array that contains N elements where N is the number of columns in the Grid. Columns(X) is the ordinal and visual reference of the Column within the Column collection.

Using the sample class defined above, the Columns() properties can be accessed in the following manner via collection e.g.

MySpecialGrid = CREATEOBJECT("MyGrid")
MySpecialGrid.COLUMNS(1).READONLY = .T.
MySpecialGrid.COLUMNS(2).HEADER1.FONTSIZE = 16
Adding Controls to Grid Columns

Column Object's CurrentControl property

By default, the grid control will display the column data using a TextBox object named Text1, i.e. GridX.ColumnX.Text1.property. The user can also ‘add’ new controls to a Column control list, use the CurrentControl property to determine what the active control is during runtime.

DEFINE CLASS MyCol AS COLUMN
CURRENTCONTROL = "MyCombo"
ADD OBJECT MyText AS TEXTBOX	
ADD OBJECT MySpin AS SPINNER	
ADD OBJECT MyButt AS COMMANDBUTTON
ADD OBJECT MYCombo AS COMBOBOX WITH
LISTSOURCETYPE = 5, ;
LISTSOURCE = MyArray
PROCEDURE ComboColor
This.MyCombo.BackColor = RGB(255,0,0)
ENDPROC
ENDDEFINE

Tip To make different controls appear on different rows, use an expression when setting the DynamicCurrentControl property, for example:

DynamicCurrentControl = "IIF( MOD(RECNO(), 2) = 0, "MyText", "MyCombo")"
Setting Paint mode for controls using the Sparse property

The user can set the Column Sparse property to .T. or .F. to determine whether the Grid paints the control only on focus (Sparse = .T., which is the default because of performance considerations). If Sparse = .F., the Grid will draw the active CurrentControl on every cell of the Column.

Bound/UnBound Column Controls

Column controls may be Bound to its associated Column ControlSource so that the data of the CurrentControl is written back to the Column Datasource. We will expose a Bound property on the Columns which is set to .T. by default so that this is done automatically.

The list of applicable Bound Controls and their related Data types follow:

Column Controls Valid Column Data Types
CheckBox Logical, Numeric
ComboBox Character, Numeric
CommandButton Character, Numeric
EditBox Character
ListBox Character, Numeric
OptionButton Character, Numeric
Spinner Numeric
Textbox Any Data Type

To add UnBound Controls to the Column, the Bound property must be set to .F.

BROWSE NAME

Use the new NAME clause on the BROWSE command to tap into the new features which the Grid control provides. This is done by adding an additional NAME clause to the existing BROWSE command. So, to set the Background color of the Browse Window, the developer can enhance their existing code in the following manner:

BROWSE customer FIELDS cno, company, contact, address NAME mybrow
mbrow.Column1.BackColor = RGB(255,0,0)
mbrow.Column2.BackColor = RGB(0,255,0)