If you’re a good programmer (all good programmers are lazy), you’ve got to be asking yourself ‘There has got to be an easier way.’ Well, there is. VFP’s authors weren’t generous enough to give us ‘defaultcontrol’ properties for our grids that would allow us to specify our custom classes as the default controls for the grid, but that doesn't mean we can’t make them.
Since these controls can’t be automatically loaded at design time, the key is to write a class that will automatically add them at run time. This is done using ADDOBJECT() and REMOVEOBJECT(). All that is needed is to loop through each of the columns of the grid, remove the default classes, and add our classes. This is easily done using the grid’s columns collection. Grid.columns(n) is an array used to refer to the nth column in a grid. When looping through all of the columns, use the following syntax:
FOR I = 1 TO this.columncount && holds # of columns … ENDFOR
FOR I = 1 TO this.columncount && columncount holds the number of columns in a grid this.columns(I).RemoveObject(“text1”) this.columns(I).AddObject(“mytext1”,”mytext”) ENDFOR
DEFINE CLASS: DEFINE CLASS “myheader” AS “header” Name = “header1” Fontbold = .T. ENDDEFINE
FOR I = 1 TO this.columncount this.columns(I).RemoveObject(“header1”) this.columns(I).AddObject(“myheader1”,”myheader”) ENDFOR
Taking this a step further, what if you want your custom textbox class for all the character fields in your datasource, but would like your editbox to display the data in your memo fields? And further still, you want all of your logical fields to be represented by a checkbox? AND you want to use your custom header class? Well, among other things, this requires more custom properties for your grid. While you’re at it, go ahead and create a property to hold the name of the class that you want to use to display each of the VFP data types. In my example, I’ll call the properties:
textclass numericclass logicalclass memoclass integerclass dateclass datetimeclass currencyclass generalclass myheader
Now you can specify a control for each datatype, and a custom header class. Granted, few of us have a separate control that we use for integers and still another for numerics, but this doesn't mean that we can’t use the same control for more than one data type.
The key to implementing different controls for different columns lies in checking the datatype of the controlsource before assigning a control to that column. We use the following syntax to do so:
Lctext = this.textclass IF TYPE(this.columns(I).controlsource) = "C" this.columns(I).RemoveObject(“text1”) this.columns(I).AddObject(“mytext1”,lctext) this.columns(I).mytext.visible = .T. ENDIF
lctext = this.textclass lcnumeric = this.numericclass lccurrency = this.currencyclass lcdate = this.dateclass lcdatetime = this.datetimeclass lclogical = this.logicalclass lcmemo = this.memoclass lcgeneral = this.generalclass lcheader = this.headerclass if type('lcheader') = "C" &&Don't use a custom header if one has not been specified llUseCustomHeader = .T. else llUseCustomHeader = .F. endif FOR lnCount = 1 to this.ColumnCount && Loop through all of the columns of the grid if llUseCustomHeader then lcColumn.RemoveObject("header1") lcColumn.AddObject("myheader1",lcheader) endif lcColumn = this.Columns[lnCount] do case case type(lccolumn.controlsource) = "C" lcColumn.RemoveObject("text1") lcColumn.AddObject("mytext1",lctext) lcColumn.mytext1.visible = .T. case type(lccolumn.controlsource) = "N" lcColumn.RemoveObject("text1") lcColumn.AddObject("mynumeric1",lcnumeric) lcColumn.mynumeric1.visible = .T. case type(lccolumn.controlsource) = "L" lcColumn.RemoveObject("text1") lcColumn.AddObject("mylogical1",lclogical) lcColumn.mylogical1.visible = .T. case type(lccolumn.controlsource) = "Y" lcColumn.RemoveObject("text1") lcColumn.AddObject("mycurrency1",lccurrency) lcColumn.mycurrency1.visible = .T. case type(lccolumn.controlsource) = "D" lcColumn.RemoveObject("text1") lcColumn.AddObject("mydate1",lcdate) lcColumn.mydate1.visible = .T. case type(lccolumn.controlsource) = "T" lcColumn.RemoveObject("text1") lcColumn.AddObject("mydatetime1",lcdatetime) lcColumn.mydatetime1.visible = .T. case type(lccolumn.controlsource) = "M" lcColumn.RemoveObject("text1") lcColumn.AddObject("mymemo1",lcmemo) lcColumn.mymemo1.visible = .T. case type(lccolumn.controlsource) = "G" lcColumn.RemoveObject("text1") lcColumn.AddObject("mygeneral1",lcgeneral) lcCcolumn.mygeneral1.visible = .T. otherwise lcCcolumn.RemoveObject("text1") lcCcolumn.AddObject("mytext1","Mytext") endcase ENDFOR
However you decide to take care of the details, this should get you pointed in the right direction for creating a grid that uses your custom classes.