Visual FoxPro FAQ Part 1

Last Update 18th January, 1997 gaa
foxfaq@iinet.net.au
C O N F E R E N C E S
Name and Contact Date and Location Cost



INDEX to TIPS

Vfp - Array Of Objects = Class Property
Vfp - Conversion Tips

Vfp - Data Encryption

Vfp - Database Properties, General

Vfp - Form Firing Orders Etc

Vfp - Grid / Pack And Environment

Vfp - Multi-threads

Vfp - Object Class Invalid For Container

Vfp - Variables, Public In Views


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=<array index of object to remove> 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.<formname>.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.<object>.method(), and so on. - save forms, menus, etc often. - If you used the TIMEOUT clause of READS, you may be forced to use FormSets to still have a TIMEOUT property (unless you want to write your own timeout handler - which is quite possible in VFP) - Look at database containers (DBCs). If you have related tables, a lot of work on 'integrity' code could be saved (i.e. use VFP's Referential Integrity RI). But N.B. setting up RI does NOT create SET RELATION TO code. You'll still have to put that in your app if you use it. - Be careful about adding tables (.DBF files) to DBCs. The table's structure will be modified and it will remain on disk as the same filename.DBF. However, previous versions of FoxPro won't be able to open them. - Re-write screens that use the *:IF directive for GENSCRNX as it doesn't convert well. - you still have to add the triggers and rules to the DBC since the converter has no way of knowing about this. - the converter will use the base classes for all screen objects. I recommend creating a subclass for each of them and using that instead.



Return to Index
VFP - DATA ENCRYPTION

From: Arnon Gal-Oz <ontime@NetVision.net.il> 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 <g> ************************************************** * 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" <mthompso@fox.nstn.ns.ca> 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 <rest deleted>



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" <prussell@fox.nstn.ns.ca>) 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"