This is long, but it might be what your looking for.
I programmatically set my grid upon startup. This allows me to change column orders, or anything after I've already been running. The following is my function that sets the column and then, some example lines on using it.
Function SetColumn
lParameters c_Field,nWide,cHeader,nCount,cTipText
local cCom,cCom2,cCom3
***>Note: abandoned cTipText.... can't do what I want
cCom3 = '"'+upper(alltrim(c_Field))+'"'
if nWide < len(alltrim(cHeader))
nWide = len(alltrim(cHeader))
endif
nWide = nWide+1
*****>Execute setup on column
cCom = "Thisform.Grid1.Column"+alltrim(str(nCount))+;
".ControlSource"
&cCom = &cCom3
cCom = "Thisform.Grid1.Column"+alltrim(str(nCount))+;
".Header1.Caption"
&cCom = cHeader
cCom = "Thisform.Grid1.Column"+alltrim(str(nCount))+;
".Width"
cCom2 = cCom
&cCom = (nWide*fontmetric(6,"ARIAL",9,"B"

)
cCom = "Thisform.Grid1.Column"+alltrim(str(nCount))+;
".Text1.Width"
&cCom = &cCom2
cCom = "Thisform.Grid1.Column"+alltrim(str(nCount))+;
".Readonly"
&cCom = .t.
cCom = "Thisform.Grid1.Column"+alltrim(str(nCount))+;
".SelectOnEntry"
&cCom = .t.
******
Thisform.Grid1.ColumnCount = 12
nkount = 0
***>Column
nkount = nkount+1
cField = "ContactName"
Thisform.SetColumn(alias()+"."+cField,fSize(cField)-4,"Name",nkount,""

*> fieldname , size , header,column#
***>Column
nkount = nkount+1
cField = "Contacttitle"
Thisform.SetColumn(alias()+"."+cField,fSize(cField)-5,"Title",nkount,""
***>Column
nkount = nkount+1
cField = "PluginName"
Thisform.SetColumn(alias()+"."+cField,fSize(cField)-5,"Plug In",nkount,""
***>Column
nkount = nkount+1
cField = "Addr1"
Thisform.SetColumn(alias()+"."+cField,fSize(cField)-5,"Address 1",nkount,""
