Return to Index VFP - ARRAY OF OBJECTS = CLASS PROPERTY
Kirby Urner
Subject: VFP arrays of objects
Q.
How do I use a table to drive a form, creating only as many
checkboxes as the table dictates, and using the table to create
the captions.
I save the checkbox data in fields that look like YYNYYYYNNNNN, where a Y
stands for a checked box, a N unchecked (the new VFP version allows
nulls as an option). I want to point my checkbox form at the list of captions, and have the form manage a character string of the form
above.
A.
Use an array as a stored property, and fill it with checkbox objects
The correct syntax for arrays of objects is to make the array a class
property (I assume that you can then change the size at some point...) and
add the objects like this:
PROCEDURE Init
FOR i=1 TO 5
THIS.AddObject('THIS.MyArray[i]','CHECKBOX') && note quotes
THIS.MyArray[i].Top=i*10
* etc.
* Does WITH work in this context do you think?
ENDFOR
To destroy the object set the Name property for each object in the array
in the Form Init event to some unique value. E.g. "arrchkN" where N=the
array index for that object. To remove the object the code looks like this:
nDestroy=
cDestroy="arrchk"+ALLTRIM(STR(nDestroy))
THISFORM.RemoveObject(cDestroy) && note no quotes!
The object will be removed from the form immediately i.e. a THISFORM.Refresh
does not seem to be needed to get the form repainted.
It might be 'cleaner' and more 'object oriented' to rewrite the second line as:
cDestroy=THISFORM.MyArray[nDestroy].Name
and to assign a genuinely unique object Name in the Init event, rather than
the serialized Names I am using at the moment (by using AMEMBERS(), perhaps).
_________________________________________________________________
That works well............
As for removing checkboxes, I don't have any
trouble with RemoveObject. I've put that in a Resize event
so the user can (within limits) resize the form and have the
checkboxes rearrange themselves (e.g. in longer columns, sorter
rows) automatically.
Here's an excerpt of my VFP DYNAFORM class definition:
PROCEDURE resize
PRIVATE nNumCols
WAIT WINDOW "Resized!" NOWAIT
nNumCols=INT((this.width-10)/150)
IF nNumCols>0
this.numpercol=this.nBoxes/nNumCols
this.height=this.numpercol*20+40
this.width=200*INT(this.nBoxes/this.numpercol)
this.killboxes()
this.mkboxes()
ENDIF
ENDPROC
PROCEDURE killboxes
FOR inc=1 TO this.nBoxes
box="this.chkbox("+LTRIM(str(inc,2))+")"
this.RemoveObject(box)
ENDFOR
ENDPROC
Kirby
Return to Index VFP - CONVERSION TIPS
CharlieGC@aol.com
Subject: Re: FPW26A to VFP
Q.
Being new to VFP, what should I look out for when converting FPW 2.6 apps to
VFP.:
A.
- copy all v2.6 app files (screens, menus, reports, etc) into new directory
- when opening old files, use 'visual convert' and put code into a text file
- if you used cleanup code to store procedures, look at moving those
procedures to 'new methods' of the form
- Study VFP's OOP syntax (e.g. 'thisform._object_._property_', etc)
- Study difference between FormSet and Form (generally its easier to
reference objects in the same formset: ThisFormSet..xxx
- Learn about assigning Forms to variables (e.g. DO FORM xyz NAME oFORMVAR
LINKED). This enables objects of the form to be accessed by
oFORMVAR.
Return to Index VFP - DATA ENCRYPTION
From: Arnon Gal-Oz
Subject: re: Data Encryption Again
Q.
How do I encrypt data in VFP.
A.
Here is an example of a en/decrypt class for VFP
based on the textbox class.
Currently it encrypts when you leave the field so you
can see it work
Move the crypt method to a subclass of a form
or to a navigation button container to make it useful.
#include discalimer.h
**************************************************
* in this version the data is encrypted when you leave the field
* so the only time u see the field decrypted is when you edit it!
* next version will encrypt/decrypt a whole form (e.g. encrypt
* only when the "save changes" button is clicked
*
*-- Class: txtencbox (c:\vfp\testproj\ontime.vcx)
*-- ParentClass: ottextbox (c:\vfp\testproj\ontime.vcx) this is just
* subclass of textbox with no additions
*-- BaseClass: textbox
*
DEFINE CLASS txtencbox AS ottextbox
*-- the passwoed to use in en/decrypting
password = "password"
*-- Unusual Bit pattern 1
PROTECTED pnbase1
pnbase1 = 21930
*-- unusual bit Pattern 2
PROTECTED pnbase2
pnbase2 = 44264
Name = "txtencbox"
*-- length of the Value
PROTECTED pnlenval
*-- temporary value
PROTECTED pctmpval
DIMENSION panpasschars[8,1]
*-- The Encrypting/Decrypting alogarithm
PROTECTED PROCEDURE crypt
dimension lanPassChars[8,1]
=acopy(this.panPassChars,lanPassChars)
lnbase1=this.pnbase1
lnbase2=this.pnBase2
new_expr=""
j=0
for j=1 to this.pnLenVal step 1
cur_chr=asc(substr(this.pcTmpVal,j,1))
cur_pass=j%7+1
lowbytebase1=bitand(lnBase1,255)
lowbytebase2=bitand(lnBase2,255)
lanpasschars[cur_pass]=bitxor(lanpasschars[cur_pass],lowbytebase2)
new_chr=bitxor(cur_chr,lanpasschars[cur_pass])
new_chr=bitxor(new_chr,lowbytebase1)
lnbase1=bitrshift(lnBase1,1)
if bittest(lnBase1,0)
lnbase2=bitlshift(lnBase2,1)
endif
new_expr=new_expr+chr(new_chr)
endfor
this.pctmpval=new_expr
ENDPROC
PROCEDURE Init
for i=1 to 8
this.panPassChars[i]=asc(substr(this.password,i,1))
endfor
this.pnBase1=this.pnbase1+this.panPassChars[2]
this.pnBase2=this.pnBase2-this.panPassChars[6]
ENDPROC
PROCEDURE LostFocus
this.pcTmpVal=alltrim(this.Value)
this.pnlenVal=len(this.pcTmpVal)
this.crypt
this.Value=this.pcTmpVal
ENDPROC
PROCEDURE GotFocus
this.pcTmpVal=alltrim(this.value)
this.pnLenVal=len(this.pctmpval)
this.crypt
this.Value=this.pcTmpVal
ENDPROC
ENDDEFINE
*
*-- EndDefine: txtencbox
Return to Index VFP - DATABASE PROPERTIES, GENERAL
From: "Miles Thompson"
Subject: Database Objects
Q.
Are database objects inherited from cursor objects?
A.
A careful reading of the help says that both tables and views are cursor
objects _in_the_data_environment_of_a_form_or_report. Within that context
their properties can be modified, e.g. to set optimistic table buffering:
this.dataenvironmentname.viewname.BufferModeOverRide = 5
where the dataenvironmentname and viewname are taken from the properties
sheet. As you know, CURSOR OBJECT help contains information on the other
properties.
CURSORSETPROP(params) could also be used to set various functions.
Buffering is set globally, unless you explicitly name the work area. Now
that raises an interesting inheritance question. If buffering is turned on
explicitly for a table, does a view created from that table inherit its
buffering? I did not try that, but I think not.
Q.
>How do I set the values of the properties of a database object? Can I only
>use functions or commands, like CURSORSETPROP() or SET FILTER, or can I do
>something like this: something.mytable.filter?
A.
Yes, but only in the context of a form or report's data environment. See
above.
Properties of views can be set in the View Designer.
Buffering and locking can be set globally with CURSORSETPROP() or from
the menu Tool/Options/Data - the settings are in the Locking and Buffering
group.
Q.
>I would think there would a
>method in the Cursor Object to set or get the filter for example. I looked
>under help for Cursor Object, and I so the properties but no methods. Can
>someone straighten me out here?
A.
See the Filter property under Cursor Object. Apparently you can set the
filter for a cursor object in the context of a DataEnvironment. There is a
cryptic note that the filter is read only at run time "when the cursor
object is accessed with CURSORSETPROP()". More testing required!!
It is confusing - because you are probably thinking in terms of "SET
FILTER", hence you are looking for a method. SET FILTER actually
establishes a state, the question we ask of it is "What is SET('FILTER')".
The filter proprerty of a cursor object is the VFP equivalent. To set it
one assigns a value ...
this.dataenvironment.cursorname.filter = "AugSales"
To find out what the filter is, query the property ...
? formname.dataenvironment.cursorname.filter
>>Do you have any other rules on the table, namely COLUMN, ROW, or UNIQUE
>>(index)? They all fire before INSERT when Buffering is off(set to 1).
>>Changing Buffering changes the firing behaviour.
>
>I have a primary index as I mentioned earlier. I tried
>CURSORSETPROP("Buffering", 5) and also setting buffering to 1. Both give
>the "Cannot update the cursor" error. It seems to me that fields in the
>database for which the triggers occur cannot be updated in the Trigger
>routines. Is this true?
I should think they have to be updateable, but I do not know and am
experimenting with this myself. For example I want to specify in the insert
trigger that every appended record child record automatically has the key
filled in with the value of the parent's key, like so ..
ON APPENDING
REPLACE child.key WITH parent.key
END APPENDING
Return to Index VFP - FORM FIRING ORDERS etc
From: a.baxter@ic.ac.uk (Alex D. Baxter [ACST])
Subject: Re: VFP - Combo Box Array
Q.
Why do VFP forms not seem to like arrays that aren't
properties? I don't see any real difficulty with it, since if you are
creating arrays on-the-fly you can always set the control properties at the
same time. But I don't understand why you can't set the RowSource to an array which should exist when the control is instantiated.
A.
This is because the form/(or any other container object) are instantiated after the object - you can by-pass the objects initiation (using the class browser) but then you'd have to initiate them manually.
Q.
What events fire first?
A.
The first events that fire are the Formset and Form Load events. See that the Load event occurs just _before_ the object is loaded into memory. Then all the form object Init events occur, then the Formset and Form Init events. So does the Formset object not exist when the Load event occurs? Perhaps I am being too classically OOP here - I would say that an object must have been instantiated to fire an event. I would also say that it is a bit nonsensical to have objects created before the container object that they are contained in is created, but who cares .... I will probably go on thinking that the Form object has been created first, but that you can't access any properties or anything in the Load event, which may be wrong but will at least maintain my sanity.
The reason all the contained objects fire first is that you can then access
their behavior (like setting them enabled, visible, etc) from the form's or
formset's Init event.
This is because the form/(or any other container object) are instantiated after the object - you can by-pass the objects initiation (using the class browser) but then you'd have to initiate them manually.
Return to Index VFP - GRID / PACK AND ENVIRONMENT
Q.
I have a Pageframe.Page container with a Grid component. I have a
speedbutton on a panel for issuing a Pack. When the
Pack button is selected, the Grid component
disappears from Page2, leaving a blank rectangle.
Issuing a refresh for the Page or Grid has no
effect.
A.
Try setting the grid.recordsource property to itself after the pack.
This.parent.grid1.recordsource = This.parent.grid1.recordsource
Return to Index VFP - MULTI-THREADS
Q.
Is VFP Multi-threaded?
i) Can I write code that will allow two querys to run simultaneously.
ii) Can I run a large query and return control to the user to continue work whilst the query is executed??
A.
VFP cannot multi-thread the internal commands.
i.) But since VFP is re-entrant you can run multiple copies of an app.
ii) Not without interfacing to a back-end server or running FoxPro twice on your machine. In theory, you could set up one program to
be the front end, and when you want to run a query, you just copy the select statement to a QUERY.TXT file. Your other instance of FoxPro just hangs out in a loop until it sees the QUERY.TXT file and then runs that select statement into a table and deletes the QUERY.TXT file. Then it resumes hanging out. Your first program could then open that table (e.g. RESULT.DBF) and show it to you.
Return to Index VFP - OBJECT CLASS INVALID FOR CONTAINER
Q.
Can someone please tell me what the following error message means and how to correct the problem?
Error Loading file - Parent Record #5
Object class is invalid for this container.
A. ("Paul Russell" )
The only time that I got this was after I had changed the number of pages in a page frame to 3, set up a form with a 3 page frame (and filled in the
pages), then reduced the number in the class to 2. The page in the form had information for a page 3 that didn't exist (because it took the default
number of pages from the class). Once I changed the class back to 3 pages,everything worked.
Return to Index VFP - VARIABLES, PUBLIC IN VIEWS
Q.
>How do I enter a public variable in the selection criteria of a view?
A. (Christoph Broeker, broeker@dart.teuto.de)
Just enter your variable with a Questionmark in the Example-Column of your Query-Generator like:
"?memvar"