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 Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Declaring Memory Vars 1

Status
Not open for further replies.

audiopro

Programmer
Apr 1, 2004
3,165
GB
Should memory variables be declared?
I have scattered memvar but I am told that the first memory var is not available.

Keith
 
Yes, it's always good practice to declare all variables, preferably at the start of each method or function.

But that has nothing to do with your problem. Whether or not you declare the variables, the SCATTER should work the same. There must be some other reason for the error. If you can give us more details of what you are doing, and what exact error you are seeing, we should be able to help.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Mike
I am issuing scatter memvar in the init procedure of a form.
The form contains fields which are set to ControlSource m.fieldname
The form works OK if I declare the memvar names in the form's LOAD procedure but I thought that scattering memvars set up the vars for me.

Keith
 
SCATTER MEMVAR does create the variables.

However, I think you are making the same mistake that you made earlier this week with the row source of your combo box. Declaring a variable in the Load event simply puts it in scope within the Load event (I'm assuming you are declaring it as LOCAL). Once the Load has executed, the variable goes out of scope.

Also, I'm not sure I get the significance of the control source. If you are setting the control source interactively in the form designer, or if you are setting it programmatically in the Init of the control, then the variable won't be visible at that point. Not only will the variable not be in scope, but it won't actually exist, because the Init of the form isn't executed until after all the controls have been initialised.

I think the best solution would be to drop the SCATTER (and corresponding GATHER, if any), and to buffer the table instead.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thanks Mike
I will look into that but I have always used Scatter and Gather as I thought that was the correct way to do it.
I have been away from FoxPro for quite a while apart from the occasional fixing of existing projects but I am finding more uses for it of late.

Keith
 
I'm not saying SCATTER / GATHER is wrong. It just seems to me to be more work, considering that buffering does more or less the same thing, with much less programmer effort.

However, if you feel more comfortable with SCATTER / GATHER, you might like to try the following approach:

1. At design time, add a custom property to your form. Let's call it oVars.

2. In the Init of the form, do [tt]SCATTER NAME THISFORM.oVars ADDITIVE[/tt]. That will create an object named oVars and store the data in its properties.

3. Also in the Init, set up the control sources. Set them to [tt]THISFORM.oVars.xxx[/tt], where xxx is the name of a field from the table.

4. Whenever you navigate to a new record, repeat the above SCATTER.

5. When you are ready to commit the user's edits, do [tt]GATHER NAME THISFORM.oVars[/tt].

I've not tested the above, but I think it should work.

Mike





__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hello Keith and Mike

Besides of calling it oRecord that's what I use and have mentioned here or somewhere else. You can also INSERT FROM NAME Thosform.oVars to create a new record or you can use this as the binding of controls of a filter defining form, then forward Thisform.oVars to a secondary form to make use of the values for creating a where clause, for instance.

So SCATTER / GATHER is also not dead for me. But if your goal is editing a DBF, why go through variables at all? With or without buffering you can set controlsources to tablename.fieldname.

As far as I learned what you do was valid for PRGs of Screens. But that's a different story in regard to the scope of variables. No matter if you declare variables local or let scatter create them, they are released at the end of Load, you have to think of the calling stack for variable scope, not of object liefetime. Private variables created by a scatter are not form properties, they are still memory variables and only live as long as the method in which they are created is part of the call stack.

What would work is scattering variables you did NOT declare local previous before you even DO the FORM or use CREATEOBJECT(), but also only, if the form is modal and therefore your form creating/callinng form would be on the call stack as long as the form runs.

Since buffers where introduced (VFP3 perhaps?) it's rather recommended you bind to tablename.fieldname and you still may save or revert what the user entered or modified by commiting the table buffer (with TABLEUPDATE) or rolling it back (with TABLEREVERT), no need to scatter the record fields to variables and gather the edited values later.

Bye, Olaf.

 
Yes, buffering was added in VFP3.

In Foxpro before VFP 3, everyone used scatter/gather because it was better than what we had before it. In dBase/FoxBase, we'd GO BOTTOM, SKIP, and then initialize empty vars from the ghost record at end of file. SCATTER did away with that requirement, so it was much better. (It's still useful, but not as often as before.)

But think about what we were doing: we were creating a buffer. Now that buffering is built into the product, we don't have to do that any more.

Boy I feel old after explaining that. [morning]
 
Dan said:
In dBase/FoxBase, we'd GO BOTTOM, SKIP, and then initialize empty vars from the ghost record at end of file.

I wish you had told me that at the time. I used to copy the fields to variables one by one.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Been looking at buffering and doing a few experiments and it all seems pretty straight forward but I must have got a bit too confident as a bit of code which has worked since I wrote it has suddenly developed a mind of it's own.
It will no doubt be another bit of bad code on my part but for some reason PAGELIST is not found anymore.
It originally worked without the DIMENSION command but now will not work with or without it.
Code:
DIMENSION PAGELIST(1)
SELECT DISTINCT PAGENAME FROM PAGES INTO ARRAY PAGELIST
THISFORM.PAGS.BUTTONCOUNT = ALEN(PAGELIST)

Keith
 
The most likely explanation is that the result set is empty. If no records are returned from the query, the array is not created (if it doesn't already exist).

But what's this got to do with SCATTER / GATHER or buffering?

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I wish you had told me that at the time. I used to copy the fields to variables one by one.

That's what I meant. But to get *empty* vars (i.e. SCATTER MEMVAR BLANK), you had to go to EOF() and use the ghost record.
 
Indeed that is not directly related to buffering, but as you assume, Mike, the result most probably is empty.

But why? Either PAGES is an empty cursor or table, or all it's records may only exist in the buffer. SQL queries doen't read from the buffer. And this is how buffering plays a role here.

If you create PAGES empty and add records to it, while it's buffered, your query does not read the buffer and would cause PAGELIST to be empty. But it would still exist and mean buttoncount becomes 1.

So a solution would be SELECT DISTINCT PAGENAME FROM PAGES with (BUFFERING = .T.) INTO ARRAY PAGELIST

Also you can turn on or off buffering for every single alias/cursor, maybe you should keep the pages alias unbuffered in this case. You typically only buffer tables, not all cursor. If you buffer query results of views or sqlexec, then you only start buffering after querying data, so only changes from the initial data are buffered. And then, when you need the table data with changes, you commit the buffer before querying data again. That way you also wouldn't have that problem.

Bye, Olaf.
 
Just a little demo code to illustrate the problem:

Code:
Release pagelist1, pagelist2
Create Cursor Pages (pagename C(10))
Set Multilocks On
CursorSetProp("Buffering",5,"Pages")
Insert into pages values ("Page 1")
Insert into pages values ("Page 2")
Select distinct pagename from pages with (BUFFERING = .t.) into array pagelist1
Select distinct pagename from pages with (BUFFERING = .f.) into array pagelist2
? Type("pagelist1",1)
? Type("pagelist2",1)
? Alen(pagelist1)
? Alen(pagelist2)

The last Alen will error, as there is no array pagelist2.

Besides this clause, which you can add per table of the FROM clause and decide to read or not read from buffered data, you could also SET SQLBUFFERING ON or OFF for a global decision, by default it's off.
And to make the confusion complete, this does not cause global buffering, but sql queries reading from the buffer, they should have named this clause and environment variable BUFFERREADING, neither BUFFERING nor SQLBUFFERING.

Bye, Olaf.
 
Very strange, I returned to the same app this morning and all is working properly, 4 records in the table and the array is found - the VFP demons have struck again!

I have read a lot of stuff about buffering and I think it makes sense but what I could do with is a simple example showing how the whole process works. I have looked at that Tastrade thing a few times before but it is simply too complex to understand all that is happening.

I set the table to the required buffering mode - got that but on a more basic level.
I want to create a new record:-
Using Scatter / Gather the blanks were scattered and the form fields were blanked, how do I blank the form fields using buffering. I can append a new record but I appear to be writing directly to the table and all data is saved anyway without the need to do a tableupdate().

Is there a simple example out there somewhere?

Keith
 
how do I blank the form fields using buffering. I can append a new record but I appear to be writing directly to the table and all data is saved anyway without the need to do a tableupdate().

You just need to do an APPEND BLANK as usual. It shouldn't be writing direct to the table. If it is, you probably have not correctly enabled buffering.

In summary, to use buffering in a form:

1. Set the control sources directly to alias.field.

2. Enable table buffering, either at the form or table level.

3. Let the user either navigate to an existing record or append a new record (or delete a record).

4. Let the user edit the data in the controls (but not if they have deleted a record, of course).

5. In your Save button, issue a TABLEUPDATE().

6. In your Cancel Edits button, issue a TABLEREVERT().

One important thing to watch for: If you have enabled record buffering (as opposed to table buffering), there will be an implicit table update as soon as you move the record pointer away from the record being edited. That might be what was happening with your blank record. If you did an APPEND BLANK, then moved the record pointer for any reason, the blank record would have been committed.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thanks Mike
That makes sense now, I will disappear into a darkened room and try it out.

I hadn't realised that it automatically does a tableupdate on exit, I suppose that makes sense. I have included a flag to say when a new file is being created and then I can do a standard check to save/ignore on exit.

Keith
 
That is so much simpler than the old Scatter and Gather.
The only thing I can't work out is how to delete records

I tried
Code:
P = ALLTRIM(THISFORM.PAGENAME.VALUE)
DELETE FROM PAGES WHERE PAGENAME = P
TABLEUPDATE()

but the record is not deleted.
I tried a SELECT with the same SQL syntax and it finds the target record.

Keith
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top