Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

vfp 8 form with grid, modify with parameters, current record fields blanked 1

Status
Not open for further replies.

clyderose

Programmer
Nov 16, 2004
26
0
1
US
I have a form with a grid and buttons. It is used to look for and select a record. In the Init, parameters are passed by array to set up the grid and the buttons appropriately for the current DBF being Added, Edited etc.
Whenever the Do Form is activated, the fields of the current record of the DBF that correspond to the controlsource for the columns in the grid are replaced with "".
What a surprise.
Any help would be appreciated.
Thanks

 
That isn't default behavior.

If you plop a grid on a form and run it, it will display the current workarea. No muss. No fuss. So this behavior is something you're causing either in property settings or in code. What have you done? Remember that we can't see what's on your screen.
 
How do you plop a grid on a form? Might be the problem. Because in other instances where I have used the modi form and set it up to exactly match my needs it is working fine and has been for years.

What I have now is a form with a grid with 10 columns and a command group with 10 buttons. All with just default properties.
Then, from MANY different PRGs with differing needs for columns and buttons, memvars contain alias() etc, arrays are loaded with control source, header and width for the columns and the Caption and width for each button. The grid and the command group are downsized to fit the needs of each program. All of this setup is done in the form initevent. The code from the initevent is below. Included in the code is a temporary window to view what it was doing during the original testing.
The bottom line is the grid formats correctly, displays correctly, the buttons also display correctly and click events work properly. The double click on the grid works properly ie selecting a record and closing the form.

EXCEPT every time you DO the form the current record has the fields used as the control source for the columns in the grid BLANKED. It happens if it is the first record or in the middle of the table. The table used is always indexed.

Again any help is appreciated and thanks,
Clyde


PARAMETERS m_formtitle,x_DOcase
PRIVATE m_formtitle,x_DOcase
thisform.AddProperty("x_Do_Case",x_DOcase)
***thisform.x_Do_Case holds the procedure with the case statements for the selected button.
#REGION 1
EXTERNAL ARRAY m_gridcols
EXTERNAL ARRAY m_cmdbtns

x_frmheight=_screen.Height*.9
x_frmwidth=0
thisform.caption=m_formtitle
thisform.Height=x_frmheight
thisform.AutoCenter=.t.
*DEFINE WINDOW temp AT 1,1 TO 30,100 TITLE "Here we go again." && USED TO WATCH THE ACTION DURING TESTING
*MOVE WINDOW temp cent
*ACTIVATE WINDOW temp
** Grid
thisform.grdList.columncount=m_gridcolscnt
thisform.grdList.height=x_frmheight-33
**?ALIAS()
thisform.grdlist.RecordSource=ALIAS()
thisform.grdlist.ReadOnly=.t.
**ColumnX etc
FOR x=1 TO m_gridcolscnt
m_columnname="Column"+ALLTRIM(STR(x,2))
** ?STR(x,2)+" "+m_columnname+" "+m_cntrlsrc
WITH thisform.grdList.&m_columnname
.fontname="FOXFONT"
.fontsize=12
.enabled=.f.
.readonly=.t.
.Controlsource=m_gridcols(x,2)
.width=m_gridcols(x,3)
ENDWITH
x_frmwidth=x_frmwidth+m_gridcols[x,3]
endf
thisform.Width=x_frmwidth+45
thisform.grdList.Width=x_frmwidth+40
**ColumnX.Header1
FOR x=1 TO m_gridcolscnt
m_columnheader="Column"+ALLTRIM(STR(x,2))+"."+"Header1"
**?m_columnheader
WITH thisform.grdList.&m_columnheader
.fontname="FOXFONT"
.fontsize=12
.Caption=m_gridcols(x,1)
ENDWITH
endf

**ColumnX,Text1
FOR x=1 TO m_gridcolscnt
m_columntext="Column"+ALLTRIM(STR(x,2))+"."+"Text1"
*?m_columntext
WITH thisform.grdList.&m_columntext
.enabled=.f.
.readonly=.t.
.value="" &&m_value
.fontname="FOXFONT"
.fontsize=12
ENDWITH
endf

*Command Group Buttons
x_cmdgrptop=thisform.grdList.Height+2 &&x_frmheight-33 &&(WROWS()*FONTMETRIC(1))-50
x_btnleft=1
x_cmdgrpwidth=0
thisform.cmdgrp.top=x_cmdgrptop
thisform.cmdgrp.buttoncount=m_cmdbtnscnt
FOR x=1 TO m_cmdbtnscnt
m_buttonname="Command"+ALLTRIM(STR(x,2))
m_width=m_cmdbtns[x,3]
m_caption=m_cmdbtns[x,2]
m_name="Cmd"+m_cmdbtns[x,1]
**?m_buttonname+" "+STR(m_width,10)+" "+m_caption+" "+m_name
WITH thisform.cmdgrp.&m_buttonname
.top=1
.left=x_btnleft
.height=27
.width=m_width
.fontname="FOXFONT"
.fontsize=12
.caption=m_caption
.backcolor=RGB(255,255,255)
.name=m_name
endwith
x_btnleft=x_btnleft+m_cmdbtns[x,3]
x_cmdgrpwidth=x_cmdgrpwidth+m_width
endf
thisform.cmdgrp.Left=(thisform.Width-x_cmdgrpwidth)/2
thisform.cmdgrp.Width=x_cmdgrpwidth

**wait
**RELEASE WINDOWS temp
*thisform.grdList.Visible=.f.

THISFORM.GotFocus
THISFORM.REFRESH
 
How do you plop a grid on a form? Might be the problem.

You click the grid on the form controls toolbar and then click on a form in the form designer.

A couple of things to consider:

* DEFINE WINDOW was deprecated somewhere around 1991.
* DEFINE WINDOW as a debugging tool has never been the best way. See DEBUGOUT in the help file.
* Use the debugger to examine the environment at the time your data "disappears"
* Use the debugger to step through construction of your grid. With something this virtual, there's probably a space in a controlsource or something like that.
* FOXFONT? Really?

Hope any of this helps!

If anyone else wants to dig through this code, here it is after a pass through Beutify:

Code:
Parameters m_formtitle,x_DOcase
Private m_formtitle,x_DOcase
Thisform.AddProperty("x_Do_Case",x_DOcase)
***thisform.x_Do_Case holds the procedure with the case statements for the selected button.
#Region 1
External Array m_gridcols
External Array m_cmdbtns

x_frmheight=_Screen.Height*.9
x_frmwidth=0
Thisform.Caption=m_formtitle
Thisform.Height=x_frmheight
Thisform.AutoCenter=.T.
*DEFINE WINDOW temp AT 1,1 TO 30,100 TITLE "Here we go again." && USED TO WATCH THE ACTION DURING TESTING
*MOVE WINDOW temp cent
*ACTIVATE WINDOW temp
** Grid
Thisform.grdList.ColumnCount=m_gridcolscnt
Thisform.grdList.Height=x_frmheight-33
**?ALIAS()
Thisform.grdList.RecordSource=Alias()
Thisform.grdList.ReadOnly=.T.
**ColumnX etc
For x=1 To m_gridcolscnt
    m_columnname="Column"+Alltrim(Str(x,2))
** ?STR(x,2)+" "+m_columnname+" "+m_cntrlsrc
    With Thisform.grdList.&m_columnname
        .FontName="FOXFONT"
        .FontSize=12
        .Enabled=.F.
        .ReadOnly=.T.
        .ControlSource=m_gridcols(x,2)
        .Width=m_gridcols(x,3)
    Endwith
    x_frmwidth=x_frmwidth+m_gridcols[x,3]
Endf
Thisform.Width=x_frmwidth+45
Thisform.grdList.Width=x_frmwidth+40
**ColumnX.Header1
For x=1 To m_gridcolscnt
    m_columnheader="Column"+Alltrim(Str(x,2))+"."+"Header1"
**?m_columnheader
    With Thisform.grdList.&m_columnheader
        .FontName="FOXFONT"
        .FontSize=12
        .Caption=m_gridcols(x,1)
    Endwith
Endf

**ColumnX,Text1
For x=1 To m_gridcolscnt
    m_columntext="Column"+Alltrim(Str(x,2))+"."+"Text1"
*?m_columntext
    With Thisform.grdList.&m_columntext
        .Enabled=.F.
        .ReadOnly=.T.
        .Value="" &&m_value
        .FontName="FOXFONT"
        .FontSize=12
    Endwith
Endf

*Command Group Buttons
x_cmdgrptop=Thisform.grdList.Height+2 &&x_frmheight-33 &&(WROWS()*FONTMETRIC(1))-50
x_btnleft=1
x_cmdgrpwidth=0
Thisform.cmdgrp.Top=x_cmdgrptop
Thisform.cmdgrp.ButtonCount=m_cmdbtnscnt
For x=1 To m_cmdbtnscnt
    m_buttonname="Command"+Alltrim(Str(x,2))
    m_width=m_cmdbtns[x,3]
    m_caption=m_cmdbtns[x,2]
    m_name="Cmd"+m_cmdbtns[x,1]
**?m_buttonname+" "+STR(m_width,10)+" "+m_caption+" "+m_name
    With Thisform.cmdgrp.&m_buttonname
        .Top=1
        .Left=x_btnleft
        .Height=27
        .Width=m_width
        .FontName="FOXFONT"
        .FontSize=12
        .Caption=m_caption
        .BackColor=Rgb(255,255,255)
        .Name=m_name
    Endwith
    x_btnleft=x_btnleft+m_cmdbtns[x,3]
    x_cmdgrpwidth=x_cmdgrpwidth+m_width
Endf
Thisform.cmdgrp.Left=(Thisform.Width-x_cmdgrpwidth)/2
Thisform.cmdgrp.Width=x_cmdgrpwidth

**wait
**RELEASE WINDOWS temp
*thisform.grdList.Visible=.f.

Thisform.GotFocus
Thisform.Refresh
 
Thank you for your response. Some replies:

*You click the grid on the form controls toolbar and then click on a form in the form designer.
I know how to add a grid in the form designer. The question was about doing it programmatically. I have an example of how to do that below.

* DEFINE WINDOW was deprecated somewhere around 1991.
* DEFINE WINDOW as a debugging tool has never been the best way. See DEBUGOUT in the help file.
* Use the debugger to examine the environment at the time your data "disappears"
* Use the debugger to step through construction of your grid. With something this virtual, there's probably a space
* in a controlsource or something like that.
The define window and question mark display helps when you have several routines deciphering the data that is being placed in the arrays to verify the proper format as it is happening. Being obsolete is not a reason to avoid using something if it can be of help. I use the window AND the debugger constantly.
The data is gone when the grid appears. There is no way to see when the grid (or whatever) is overwriting the fields.

* FOXFONT? Really?
I find it to give a much better appearance and is easier to read when displaying a grid, browser or vertical lists. In other areas I use Arial primarily, although sometimes the customer has their own preference.

So, new info is that if I programmatically add the grid and don't use arrays to set the properties in the existing forms init event it does not overwrite the data in the table. So NO problem if NO array. That looks like your idea about a space in the controlsource entry or something like that to be where to look AGAIN. It was my first thought. But I still don't see how that would cause a ONE time screwup and then work flawlessly. Aw foolish me, it isn't like it hasn't happened before with VFP.
Again any thoughts would be appreciated.
Thanks, Clyde


thisform.AddObject('grdList','Grid')
WITH thisform.grdlist
.columncount=m_gridcolscnt
.RecordSource=ALIAS()
.ReadOnly=.t.
.fontname="FOXFONT"
.fontsize=12
.allowheadersizing=.f.
.allowrowsizing=.f.
.deletemark=.f.
.height=x_frmheight-33
.left=0
.readonly=.t.
.rowheight=15
.top=0
.width= 200 && for now
.forecolor=RGB(0,0,0)
.highlightstyle=1
.allowautocolumnfit=2
.allowcellselection=.f.
.name="grdList"
.enabled=.f.
.visible=.f.
ENDWITH
*******************************xxxxx
* ,'CODE+"|"+IIF(SEEK(code,"arc"),LEFT(arc.name,14),"NOT FOUND ");
* +"|"+DTOC(date_in)+"|"+dyer_no+" |"+dyer_po+" |"+LEFT(cust_po,10)+"|"+IIF(invoiced,"Done"," ")'
WITH thisform.grdlist
.columncount=2
.column1.fontname="FOXFONT"
.column1.fontsize=12
.column1.enabled=.f.
.column1.readonly=.t.
.column1.movable=.f.
.column1.resizable=.f.
.column1.forecolor=RGB(0,0,0)
.column1.Controlsource="code"
.column1.width=80
.column1.header1.fontname="FOXFONT"
.column1.header1.fontsize=12
.column1.header1.Caption="Code"
.column1.text1.enabled=.f.
.column1.text1.readonly=.t.
.column1.text1.borderstyle=0
.column1.text1.margin=0
.column1.text1.fontname="FOXFONT"
.column1.text1.fontsize=12

.column2.fontname="FOXFONT"
.column2.fontsize=12
.column2.enabled=.f.
.column2.readonly=.t.
.column2.movable=.f.
.column2.resizable=.f.
.column2.forecolor=RGB(0,0,0)
.column2.Controlsource="date_in"
.column2.width=80
.column2.header1.fontname="FOXFONT"
.column2.header1.fontsize=12
.column2.header1.Caption=m_gridcols(x,1)
.column2.text1.enabled=.f.
.column2.text1.readonly=.t.
.column2.text1.borderstyle=0
.column2.text1.margin=0
.column2.text1.fontname="FOXFONT"
.column2.text1.fontsize=12
.enabled=.t.
.visible=.t.
ENDWITH
 
You misunderstand much of what I wrote, I think.

You asked what plop means. I explained.

Your DEFINE WINDOW alternative is just an outdated and long-hand way to do something that is BUILT INTO THE PRODUCT and the built-in version does not interfere with the event model or the object model. Instead of printing values to a window created for the purpose, use the DEBUGOUT command instead which send output to the debugger's output window. You also never have to worry about commenting out your debugging code because it is ignored at runtime, unlike your DEFINE WINDOW and ? commands.

FoxFont wasn't the best option in FoxPro 2.x. It was absolutely necessary because FoxPro itself used FoxFont to calculate between Pixels and its native Foxels, a unit of measure no longer in use. But it was the absolute worst font to use in a Windows application. It causes problems because it is not a TrueType font.

Since you have proven that the data displays properly when you allow the product to do its native behavior, it's now incumbent on you to discover what you're doing to mess that up.

I can absolutely guarantee that if you hired anyone who answers questions around here to help you figure this out, the very first thing any of us would do is fire up the debugger to discover how the values you expect are differing from the values you're actually getting.

Do you need help understanding how to use the debugger?
 
The default is Arial, and we fought long and hard to get it that way. If you find Arial not to your liking, any TrueType font should work. For a mono-spaced font, Courier New is usually the TrueType choice.
 
Well the problem was:

If you modify the grid column controlsource programmatically using memory variables then the current field referenced is blanked during the form initevent.

m_var="arc.code"
.controlsource=m_var ..........will blank the field

The solution is:

.controlsource="arc.code" .... works fine.

m_var="(arc.code)"
.controlsource=m_var ..........works fine.

Yep adding parenthesis did the trick. Why you ask? Who the heck knows. Just another VFP anomaly.

Have fun.
 
Sounds more like you've bumped into known (and intentional) behavior. Rather than just calling it an anomaly, why not try to understand it so you won't play directly into it next time?

By the time execution gets to a form's init method, all controls on the form have already been through their own init methods. They have all of their defaults already established. This is simply bog standar4d behavior of VFP's forms and controls and you do really need to understand it.

In some circumstances (like closing a table, and apparently messing with controlsource at the wrong time), the controls contained in a grid will deconstruct.

If that's what you're running into, it's better to learn about it and avoid it in the future don't you think?
 
I just tried to repro, it can't be only that (in VFP9).

Setting controlsources at form init doesn't blank a field. The only reason the parenthesis stops something from blanking the current row is, you make the controlsource an expression, instead of a simple field, which makes the grid column readonly in itself, expressions, even if they just differ from a field or variable name slightly by this parenthesis, are considered a one way and so the controlsource only reads from the field, it doesn't try to write back.

There must be something else causing a blank row.

If you only need the grid readonly, that's a solution anyway.

Bye, Olaf.
 
Thanks for the responses.

danfreeman:
Under NO circumstances should "Do"ing a form blank fields in a database. That is scary behavior. The grid is READONLY.
The form is not opening or closing a table.
Where is the documentation for this known behavior? I could not find it.

OlafDoschke:
Your description "Setting controlsources" etc is the way I have always understood it to work. But I never tried doing it with an array before.
The grid is readonly from form design and stays that way during the programmatic changes that are made.
Are you saying you could not duplicate it in VFP9? I didn't try it with VFP9. This particular client is still on VFP8.

The whole blanking the fields thing really shocked me.

Thanks again,
Clyde

 
Yes, I said I couldn't repro it in VFP9. I didn't try your code, there's much too much missing, eg I don't have your tables, of course. Maybe it depends on field types.
But I put controlsources in an array and set them from there.

What dan is saying that a grid going blank for too late setting of controlsources is known behaviour, not blanking records. Are you really sure your data is blanked and not just the grid?

Bye, Olaf.
 
What I did is just this:

Create a form, put a grid on it (Grid1)

In Load Do:
Create Cursor curTest (iID I Autoinc, cText C(12))

For i = 1 to 8
Insert into curTest (cText) Values (Sys(2015))
EndFor
Go Top

In Init Do:
Dimension m_gridcols(2,2)
m_gridcols(1,2)="curTest.iID"
m_gridcols(2,2)="curTest.cText"

For i = 1 to 2
thisform.grid1.Columns(i).Controlsource = m_gridcols(i,2)
endfor

run the form, grid shows all records, nothing blanked.
 
Yes, your test works in VFP8.
Yes, I am sure the fields are blanked and written back to the table.

After doing some more experimenting, this is what I have found.

Using the original code (please reference the beautified version supplied by Danfreeman above) I was using FOR to step through the columnX definitions THEN another FOR to step through the ColumnX.HeaderX defs, then again for the ColumnX.textX defs. (How inefficient! But hey I was still experimenting!)

That caused the fields to be overwritten and saved back to the table. Adding the parenthesis in the arrays eliminated the problem.

Then:
I combined the redefining into ONE FOR operation and the parenthesis are NOT required to prevent the problem. Works properly with or without the parenthesis.

So, it appears that redefining PART of a column and its associated components separately caused the problem?

Thanks for your input,
Clyde


 
Had a few minutes so,
Below is code that duplicates the "blanking a field and saving it to a table" behavior:

In TEMP.PRG paste:


Code:
Create Cursor curTest(iID c(5), cText C(12))

For i = 1 to 8
 Insert into curTest (iId,ctext) VALUES (STR(i,5),STR(i*2.7,12))
EndFor 
IF file("curtest.dbf")
  DELETE FILE curtest.dbf
  DELETE FILE curtest.cdx
endif
COPY TO curtest.dbf
CLOSE ALL
USE curtest
INDEX ON iId TAG iId
SKIP 3

Dimension m_gridcols(2,2)
 m_gridcols(1,1)="HD iID"
 m_gridcols(1,2)="iID"
 m_gridcols(2,1)="HD cText"
 m_gridcols(2,2)=" cText"
 
 
 DO FORM temp
----------------------------------------------------------------
Create form TEMP, place a default grid on it.
In FORM TEMP initevent paste:

Code:
EXTERNAL ARRAY m_gridcols

* For i = 1 to 2
* thisform.grid1.Columns(i).Controlsource = m_gridcols(i,2)
* endfor
m_fontNAME="COURIER NEW"
M_FONTBOLD=.t.
M_FONTSIZE=12
WITH thisform.grid1
 .columncount=2
 .allowaddnew=.f.
 .RecordSource=ALIAS()
 .recordsourcetype=1
 .ReadOnly=.t.
 .fontname=M_FONTNAME
 .fontsize=m_fontsize
 .fontbold=M_fontbold
 .allowheadersizing=.f.
 .allowrowsizing=.f.
 .deletemark=.f.
 .rowheight=15
 .forecolor=RGB(0,0,0)
 .highlightstyle=1
 .highlightbackcolor=RGB(10,36,106)
 .highlightforecolor=RGB(255,255,255)
 .scrollbars=1 
 .allowautocolumnfit=2
 .allowcellselection=.f.
 .scrollbars=2
 .tabindex=1
 .tabstop=.t.
 .enabled=.t.
 .visible=.t.
ENDWITH

FOR x=1 TO 2
  m_columnname="Column"+ALLTRIM(STR(x,2))
  WITH thisform.grid1.&m_columnname
    .fontname=M_FONTNAME
    .fontsize=m_fontsize
    .fontbold=M_fontbold
    .enabled=.f.
    .readonly=.t.
    .Controlsource=m_gridcols(x,2)
  ENDWITH
endf
FOR x=1 TO 2
m_columnheader="Column"+ALLTRIM(STR(x,2))+"."+"Header1"
  WITH thisform.grid1.&m_columnheader
   .fontname=M_FONTNAME
   .fontsize=m_fontsize
   .fontbold=M_fontbold  
   .Caption=m_gridcols(x,1)
  ENDWITH
endf
FOR x=1 TO 2
m_columntext="Column"+ALLTRIM(STR(x,2))+"."+"Text1"
  WITH thisform.grid1.&m_columntext
    .enabled=.f.
    .readonly=.t.
    .value=""                           
    .fontname=M_FONTNAME
    .fontsize=m_fontsize
    .fontbold=M_fontbold
  ENDWITH
endf
 
Clyderose,

I've come into this thread late, so my apologies if I am asking you something that has already been resolved.

I just ran your code, and I can see both fields in the current record being blanked, just as you originally stated. Obviously, it is the line .value="" that is causing that.

I'm not clear why you have the above line in your code. Everything seems be OK without it. It was not in Dan's version of the code.

Perhaps you could clarify that.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hello and thanks for your response.

.VALUE="" is in the code that was beautified above, look for this:
Code:
*?m_columntext
    With Thisform.grdList.&m_columntext
        .Enabled=.F.
        .ReadOnly=.T.
        .Value="" &&m_value
        .FontName="FOXFONT"
        .FontSize=12
    Endwith
Endf

Now, go back into the form and put .value="" back in place.
Do Temp, the fields display blank in the current row. You can move through the other records fine. NO blanking.
The issue can be seen by closing the form,
use CURTEST and browse. (It is still there, it isn't erased until you run TEMP again)
The "blankS" were SAVED back to the table. Overwriting the original data.
The grid is readonly. The columns are readonly.

Have fun,
Clyde



 
Oops! Forgot this part.

NOW go back in TEMP.prg
and add parenthesis as below:

Dimension m_gridcols(2,2)
m_gridcols(1,1)="HD iID"
m_gridcols(1,2)="(iID)"
m_gridcols(2,1)="HD cText"
m_gridcols(2,2)="(cText)"

and the blanking problem disappears.
 
Yes, I'm seeing the same. I understand what's happening, but I can't explain why.

By the way, the fact that the grid is read-only is irrelevant. With any control, you can programmatically set a value, regardelss of whether the control is read-only.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top