This short tutorial is for programmers who are considering a move to Visual FoxPro from
another programming language. The pages will lead you through the development of a very
simple database program. It only has one table and one form but the tutorial will cover the
important features of the language. Links from the main thread of the programming tutorial will
take you out to other pages covering aspects of Visual FoxPro which aren't immediately relevant
but which are useful.
Although it is simple, this application is based on a real-life example, it's an early stage of the
VFP database which we use in the office to hold details of our programming CDs. We have been
gathering CDs over the past ten years - over a thousand in all - and they're a mixture of
invaluable paid-for programs (like VFP), free utilities which might come in useful, and backup
copies of previous work. Until we built this database, we could never find the disk we wanted.
Each now has a unique ID number and they are stored on the shelf in numerical order. If ever I
need that CodeBook CD for VFP 3 again then the database tells me where to find it. The
database also holds the Serial Number and Registration Key in case we lose the original slip of
paper.
We'll start the tutorial with a description of the Visual FoxPro user interface, then we'll create a
table, describe the programming necessary to build a form that will display the data, and the
development of an executable. Links to the next six pages give step-by-step instructions:
The screenshot shows part of the Visual FoxPro environment with a few lines of Fox commands
showing in the Command Window. That window is shown docked against the left-hand side of
the screen. It can float free or be docked against any edge of the screen and in real life it would
probably be wider with a smaller font size. The black pane on the right of the window is where
the results of commands are displayed.
IntelliSense
The keywords of the FoxPro language appear as upper case in blue because this is the default
setting of Visual FoxPro's Intellisense feature. As soon as Fox recognises the word that you are
typing it displays the rest of that word in blue. If you press the Space or Tab keys then Fox will
complete the word for you and follow it with a list of parameters and options that can apply to
that command. Unlike other Microsoft languages, the Visual FoxPro IntelliSense is open and
documented - it is actually a lookup into a FoxPro table - and you can add your own entries to
the list.
Just to take a simple example, you can create a new program file (code module) by selecting
New from the File menu and specifying that you want a new file of type Code. It is so very much
quicker though to type mc in the Command Window and hit Space or Tab. Intellisense will
expand this abbreviation to Modify Command and you can either hit Return to get a new file,
type "?" to see a list of program files, or type in the name of the file you want to open.
The screenshot shows the Project Manager docked with the documents tab expanded to show
that there are two forms in this project. The mycd form is shown in bold because this is the main
form in the project, the one that will appear when the executable runs. Note that, unlike in
Microsoft Access, you do not have to have a form as the main component of the project. In fact it
is more normal to start with a program that sets up the correct environment and displays a menu.
None of the buttons from the full display are visible when the Project Manager is docked like
this but all their functions are available on a right-click menu.
If you do want to able to keep one of the pages visible whilst the Project Manager is docked then
you can tear that tag off. Just click on its caption and drag it onto the FoxPro desktop. A close
widget will appear on the tab. Click that to close the floating tag and return it to the docked
position.
Designing a table
We will skip the first and most important phase of this process and assume that the structure of
the table has already been considered. This project has a single table named CD with the
following structure:
Field
Type
Size
Description
CDID
Publisher
30
CDName
30
SerialNo
40
Key
40
Security Key
CDDate
Date received
Creating a table
Click on the Data tab of the Project Manager then right-click on Free Tables. This simple
application will only have a single table and does not need the overhead of a database.
Select New File then New Table from the dialog that appears. This dialog allows you to start the
Table Wizard which can be useful if your application matches one of the templates provided.
An explorer dialog will appear offering to create a table named 'Table1.dbf'. Change the name to
'CD.dbf' and save it in the same folder as the project manager file. A real life project typically
has its files in a directory tree structure but we'll put all the files in the same folder here for
simplicity.
The Table Designer will appear. Add the six fields from the list above and click OK when you
have finished. Note that no size was requested for the Integer and Date fields, the size of these
data types is fixed by FoxPro.
The greyed-out fields on the right of the designer are only available for tables which are part of a
database. You can leave the main route through the tutorial and go to this page to learn about
Visual FoxPro databases.
This shows that the table named 'CD' is open, it's open for your exclusive use, it holds three
records and the record pointer is on the first record.
Type:
Browse
Do this three or four times and add some data to the table so that you will have something to
work with when you design a form.
Create a form
Click on the Documents tab of the Project Manager then right-click on Forms. Select New File
then New Form from the dialog.
The Form Designer will appear:
The screen shot shows the Form Designer and the Form Controls toolbar with the mouse
positioned above the Button control so that its tooltip is displayed.
Add data
The form has to be connected to a data table. Right-click on the form and select Data
Environment .... A directory tree will open so that you can select a table. Click on CD.dbf then
close the Add Table dialog. This should leave you with the form and the Data Environment
windows visible:
Use the mouse to select the six fields from the Data Environment and drag them to the form. If
you do this with a normal left-click then FoxPro will automatically create a grid control for the
fields. Start the drag with a right-click instead. Note that the tooltip will show you the size and
type of the field as you select it.
When you drop the files a menu will appear with the option of showing the fields as a grid or as
multiple controls. Select the Create Multiple Controls Here option. Make sure that you move the
mouse to the top-left corner of the form before you drop the fields. Some of the fields are quite
wide and you might have to make the form a bit larger to accept them it. Just click on the form
border and drag it to the size you want.
Close the Data Environment and leave the Form Designer on screen.
You will be asked to save the form before you can run it. FoxPro will suggest a name something
like 'Form1.Scx'. Change this to 'MyCD.scx' or something more suitable but do not change the
file extension. Form data in Visual FoxPro is stored in a pair of files with 'scx' and 'sct'
extensions. The 'scx' file is actually in VFP dbf format and the 'sct' file holds its memo fields in
fpt format.
Note that the file name is not the same as the form name. The form name is a property of the
form.
the colour is just the basic Microsoft grey. All these can be improved by altering the properties of
the form and controls. Properties are covered in the next page.
ThisForm is the FoxPro equivalent of Me in Access and refers to the form which holds this
object. As you type the period a list of possible methods will appear. By the time that you have
typed 'rel' Fox will have identified that you want the Release method and will pop up a tooltip to
identify it. Press Enter to confirm.
Close and save the code window by pressing CTRL+W or by clicking the Save button on the
toolbar. Then press CTRL+E or the exclamation mark on the toolbar to run the form.
Click the button and the form will close and return you to the Form Designer. The caption on the
button is not quite right and we will correct this by changing the Caption property of the button.
Right-click on the button and select Properties... from the menu.
Control properties
FoxPro is a flexible object-oriented system with a wide range of properties. You can reduce the
number displayed so that you only see those which have been changed from their default values.
Right-click on the name 'Command1' at the top of the Properties Window and select Non-Default
Properties Only from the menu. This will filter the list to just the seven properties shown.
Click on the Caption property and type Close as a new value. Note that you cannot type where
the value is shown in the list, you have to type the new value of the property into the textbox
above.
Whilst you are in the Properties Window you can also change the name of the control from its
default value of "Command1" to something more informative. You can see amongst the
properties that the Click event holds a 'User Procedure'. This code is part of the object and will
still be a part of the object if you change the object's name. Visual FoxPro does not suffer from
the problem that Access and Basic have where changing the name of a property breaks the link
to its methods and leaves you with an orphan.
Navigation buttons
Follow the same technique to add two more buttons to the form and change their Caption
properties to read 'Prev' and 'Next'. Double-click on the 'Prev' button and type this code into its
Click event:
* Move to the previous record and refresh the form
Skip -1
ThisForm.Refresh
The code in green is a comment. If a line starts with an asterisk then everything on that line
becomes a comment and is ignored by the compiler.
Close the edit window, double-click on the 'Next' button and type this very similar code into its
Click event:
Add two more buttons to go to the first and the last record. The FoxPro commands are:
* Move to the first record and refresh the form
Go Top
ThisForm.Refresh
and
* Move to the last record and refresh the form
Go Bottom
ThisForm.Refresh
These four buttons are so similar that we would be thinking about subclassing them all from the
same source in a real system.
Prev button
This button will move us to the previous record in the table so we must make sure that the user
cannot try to navigate beyond the first record. An If statement in the click method of the Prev
button will detect whether we are trying to move to the record before the first one and this code
will prevent the user seeing an error message.
It uses the BOF() function to determine whether we are at "Beginning of File":
* Prevent the Prev button going too far
If Bof() Then
* Do nothing - we are already on the first record
Else
* Skip to the previous record
Skip -1
EndIf
The Then in the first line is optional. Anybody who works in Visual Basic as well as in FoxPro
will already be in the habit of adding it because it's compulsory in that family of languages. The
final EndIf is one word. You will get a syntax error if you use two words in VB style End If.
The Else clause is optional but the components of the If structure must always be on separate
lines.
Next button
The Next button needs to detect whether we are at "End of File" to prevent the user moving
beyond the last record. It has similar code using the EOF() function but the logic has to be more
complex because the EOF() function does not become true until after the record pointer has
moved beyond the last record.
* Prevent the Next button pushing us off the end of
* the data
If Eof() Then
* We've already fallen off - go to the last record
Go Bottom
Else
* Skip to the next record
Skip 1
* Has this move made us fall off?
If Eof() Then
* We have fallen off - go to the last record
Go Bottom
Else
* Do nothing - we're safe
EndIf
EndIf
Enabling buttons
Preventing the user from seeing these error messages improves the usability of the form. Another
improvement would be to set the Enabled property of the Next and Last buttons false when we
are on the last record. This will grey out the buttons to make it obvious that the user cannot move
any further in that direction.
ThisForm.cmdNext.Enabled = .F.
ThisForm.cmdLast.Enabled = .F.
We will need similar commands to disable the Prev and First buttons when on the first record.
Note that you have to give the full names of the buttons. They have no independent existence so
you must specify them completely.
True and False values are represented by .T. and .F. in FoxPro. They are a separate logical data
type and are not related to integers in any way. FoxPro uses .Null. to represent a null value in any
data type.
Scope of variables
Visual FoxPro has three levels of scope for variables. These are declared by the Local, Private or
Public keywords. Variables can be declared anywhere in code before the point where they are
first used but the best place to declare them all is at the start of the program or module.
Public variables
A public variable is available to all code in the program. Any statement anywhere is able to
modify its value so a bug involving a public variable can be very difficult to track down. Despite
that danger, a few carefully chosen public variables can simplify a program design. If you
declare the user's ID as public:
public glUserID
then you can read the value at login and be able to use that value everywhere else in the program.
That's a useful facility as long as the value of the variable is only ever set in one place.
One other danger with public variables is that they persist in the development environment after
the program has finished executing. It is not unknown for a program to run successfully on the
developer's PC and to fail on a user's PC because it relied on the continuing existence of a public
variable left over in the development environment from previous run of the program.
Private variables
Private variables are something of a hangover from early versions of FoxPro where they were the
only alternative to a public variable. A private variable is available in the program where it is
declared and in all programs which are called from that program. The scope of the variable is
limited to some extent so it is slightly safer than a public variable. This was the only alternative
available in versions 1 and 2 of FoxPro but is rarely used in Visual FoxPro.
If the customer's name is declared as:
private pcCustomer
then all the routines called from this program would have access to that variable. Some
developers would take advantage of this availability to avoid having to pass the value across as a
parameter.
If a variable is not declared before it is used then it is created with a default private scope.
Local variables
Local variables were introduced with the launch of Visual FoxPro as FoxPro version 3. As their
name suggests, a local variable is only available in the program in which it is declared. If you
declare a variable such as:
local lnCount
then you know that nothing outside of that program can read or change the value of lnCount.
Debugging becomes much easier and for this reason, most variables used within a program will
be declared as local.
Variable names
Variable names can consist of any combination of letters, numbers and underscores and are not
case-sensitive. The name must start with a letter or underscore.
Names can be up to 128 characters long in Visual FoxPro. Be careful when working with version
2.6 or anything earlier because only the first ten characters of a name were significant. If you had
two variables named lnTimeForPainting and lnTimeForPreparation then FoxPro would treat
them both as the same variable with the ten-letter name lnTimeForP. The program will run and
give answers that are nearly, but not quite, correct.
You have to be very careful when writing FoxPro programs. You might declare a local variable
named lnPrice but if you make a typing mistake later on and store a value in a variable named
lnPrce then FoxPro will leave your original lnPrice unchanged and will create a new private
variable named lnPrce to hold the value.
Naming convention
Microsoft have supported a simple naming convention for FoxPro variables. Each name has a
two-character prefix. The first letter of the prefix describes the scope of the variable, the second
letter describes the variable type:
Scope
Type
c Text - or character)
l Local
d Date
t Parameter
l Logical
n Numeric
o Object
t Datetime
y Currency
Note that these conventions are purely for the convenience of the programmer. FoxPro does not
analyse the prefix. The program will compile and run successfully even if you give a misleading
name such as ldBirthday to a public variable holding the user's logon name.
Selection
Selection structures determine whether the program should execute one section of code or
another. The FoxPro syntax supports two ways of making this choice:
If
Do Case
Repetition
Repetition structures determine how many times the program should execute a particular section
of code. FoxPro supports three types of repetition:
If _TALLY = 0 Then
Wait Window 'No records found'
Else
Copy To TmpFile.xls Type XLS
Wait Window 'Exported to Xls'
Endif
If the expression _TALLY=0 evaluates as true (.T. in FoxPro) then the statements between If and
Else will be executed.
If the expression evaluates as false (.F. in FoxPro) then the statements between Else and EndIf
will be executed.
Notes
_TALLY is a variable maintained by FoxPro which holds the number of records processed by
the last command.
The condition must evaluate as .T. or .F. because the logical values in FoxPro are a separate data
type and an integer result will not be interpreted as a logical value.
The Then is optional but does no harm. If you are used to working in the VB family of languages
where the word is compulsory then you will probably be in the habit of adding it automatically.
The keyword EndIf is a single word. If you switch between using VB, Access and FoxPro then
you will continually be making the mistake of writing it as two words.
The Else clause is optional and the structure can just consist of If ... EndIf.
The components of the structure must be on separate lines.
There is no ElseIf clause. Use a Do Case structure when you want to select between more than
two choices.
Back to FoxPro program control .
Do Case
Case _TALLY = 0
Wait Window 'No records found'
Case _TALLY = 1
Wait Window 'One record found'
Otherwise
Wait Window 'Many records found'
EndCase
Each Case statement is followed by an expression which must evaluate to true or false. FoxPro
evaluates each of these in sequence.
If the expression following the first Case statement evaluates as true (.T. in FoxPro) then the
statements between this Case and the next one will be executed. The rest of the structure will be
skipped and execution will continue on the line following the EndCase statement.
If the first expression evaluates as false (.F. in FoxPro) then the next Case statements will be
evaluated in turn until one is found to be true. If none are found to be true then the code
following Otherwise will be executed.
Notes
_TALLY is a variable maintained by FoxPro which holds the number of records processed by
the last command. It is very useful in situations like this where you need to know how many
records have been found.
Each logical condition must evaluate as either .T. or .F. because the logical values in FoxPro are
a separate data type. Unlike in many other languages, an integer result will not be interpreted as a
logical value.
Be careful to get the tests in the right order when designing a Case structure. Remember that the
expressions are evaluated in sequence and put the toughest test first. If for example you need to
test whether something is greater than 1 or greater than 10 then you must test for greater than 10
first. If you test for greater than 1 first then a value such as 11 would pass that test and the greater
than 10 test would never be reached. This sort of mistake can be difficult to detect in tests
because the program runs without error and will give the right result most of the time.
The Otherwise clause is optional. If it is not included and all the individual Case statements
evaluate as false then none of the code will be executed.
It is good practice to include an Otherwise clause even if there is no action which needs to be
taken. If you are positive that the individual Case statements cover every possible situation then
add an Otherwise and display an error message.
Each Case can have an expression based on a different variable. This example works out the
method of delivery from the value of the order, the weight of the goods and the country to which
it has to be delivered.
Do Case
Case lyCost > 1000
*-- Free delivery for large orders
lcDelMethod = 'Free'
Case lnWeight > 10
*-- Buyers must collect cheap, heavy orders
lcDelMethod = 'Collect'
Case lcCountry <> 'UK'
*-- Airmail for a light, cheap, overseas delivery
lcDelMethod = 'Airmail'
Otherwise
*-- Must be light, cheap, inland delivery
lcDelMethod = '2nd class mail'
EndCase
The code in this example will execute ten times and will print the numbers from one to ten.
Notes
The Next lnCount marking the end of the structure can be replaced by EndFor but you may find
it easier to use the Next option because it is the same form as in Visual Basic and Access.
Executes a section of code several times (zero, one or many times) whilst an expression remains
true. This example will keep keep adding to a total until that total reaches 100;
lnLimit = 100
lnTotal = 0
Do While lnTotal < lnLimit
*-- Keep adding until we hit the limit
lnTotal = lnTotal + lnNextItem
Print lnTotal
EndDo
If the expression lnTotal < lnLimit evaluates as true (.T. in FoxPro) then the statements in the
loop will be executed and the expression will be evaluated again. The loop will continue until the
expression evaluates as false (.F. in FoxPro).
If the expression evaluates as false when FoxPro first reaches it then the statements inside the
body of the loop will never execute.
The code in this example will keep adding new items until the total exceeds the limit.
Notes
The test condition must evaluate as .T. or .F. because the logical values in FoxPro are a separate
data type and an integer result will not be interpreted as a logical value.
This is the only form of the while loop in Foxpro. There is not an alternative form with the
expression being tested at the end of the loop and there is not an inverted form which runs until
the expression evaluates as true.
Else
* No rise or bonus for the other employees
Replace Bonus With 0
EndIf
EndScan
The code in this example will modify every record in the Staff table and reward the managers.
Notes
This example shows how one control structure can be embedded within another. The If structure
is executed once for every record in the table.
Build Options
The standard version of Visual FoxPro lets you build executables and DLLs which can be freely
distributed without paying additional licence fees. Select the Win32 Executable option and select
the Display Errors tick box. Then click OK to build the executable.
This will start the event processing loop but we now need to stop the loop when the form closes.
Double-click on the Close button and change the program code in its Click event to read:
Thisform.Release()
Clear Events
Save and close the form and use the Project Manager to build the executable again. You should
now be able to close FoxPro altogether, navigate to the executable in Windows Explorer, and run
the executable by double-clicking on it.
The site has more details on stopping and starting the event-handling loop.
Select your Visual FoxPro application from the list then click the End task button. You will be
warned that this is an extreme act and asked to confirm that you do indeed want to cancel this
process. Click OK and wait. Windows may take several seconds to complete the task of closing
down the application. When it has been closed you will be told that you have terminated FoxPro
prematurely and asked whether you want to report the problem to Microsoft. We have been
reporting this for ten years now so I suspect it will be a waste of time to report it again.
Now that you have cancelled the application, close the Task Manager and open your project up
again in FoxPro.
Solution
The problem arises because Visual FoxPro is event-driven. The RunTime engine opens your
executable and then responds to events as they occur. You have closed your application but not
told FoxPro to stop waiting for events.
The command to stop the event-processing loop is:
Clear Events
and FoxPro must execute this command whichever way that the application closes down.
Depending on the structure of your application you might put the command is several different
places:
You'll need to add this code in different places depending on whether you are using a form, a
menu or a program as the main element of your application.
If you are using a form then add this as the last line in the Activate event. This will allow the
form to load and initialise itself before going into the event processing loop and waiting for
mouse and keyboard events.
In a menu, add it to the CleanUp code snippet. Select General Options from the View menu then
click the Cleanup... tick box. An edit window will open behind the dialog; click OK to close the
dialog window and the CleanUp edit window will remain:
If you have a program as the main element of your project then add the Read Events line
immediately after you have set up the user interface by loading a form or menu. Fox will then
stop executing this sequential code and will start monitoring keyboard and mouse events, waiting
to see what it should do next.
This will start the event processing loop but we need to stop the
loop in order to close the application. If you forget to do this then you'll hit the second mostcommon problem - the "Cannot quit Visual FoxPro." message.
You avoid this by using the Clear Events command to stop the event-processing loop. Execution
will then continue from the line following the Read Events command in the main program.
to see all the customers in the USA. If you are convinced that your selection is correct then you
can take the cursor back up to that line and change the first word so that the command becomes:
delete for country='USA'
You have made no change to the selection criterion so you can be certain that you will be
deleting the correct set of records. If you wanted even more reassurance, you could have edited
the command to read:
copy to USAList type Xls for country='USA'
and exported a list of the records that are about to be deleted into an Excel spreadsheet. Many
FoxPro commands share a similar syntax and you can save a lot of time and typing by just
modifying earlier entries in the Command Window.
SQL
The example above used traditional dBase commands but Visual FoxPro also accepts SQL
commands natively. You can type a command like:
select cust_id, company, country ;
from customer ;
where country='USA' ;
into cursor csrUSA
into a program or into the Command Window and select the name and ID of all the USA
customers into a temporary table. This SQL capability means that FoxPro databases can easily be
upgraded to run on larger systems such as SQL Server, MySQL, or Oracle servers. SQL is also
very useful for populating listboxes and combo boxes as a form loads.
Note that the semi-colons here are nothing to do with the syntax of SQL. The semi-colon is the
FoxPro line-continuation character and indicates that this is really a single command.
Help
Press F1 or type help to open the Help system.
FoxPro is a self-contained language. Although it does integrate well with the rest of the
Microsoft family you do not need to call on such things as ADO or Common Control DLLs or
.Net in order to write a FoxPro system. The Help system is also self-contained and loads quickly
because it is a single chm file.
FoxPro comes with a sample database of customers, invoices and stock tables in C:\Program
Files\Microsoft Visual FoxPro 9\Samples\Data or in the equivalent folder on earlier versions of
Visual FoxPro. This is only a small database with a few hundred records but it is a useful
resource when you are learning. It is wise to copy the entire folder to your own folder before
starting to use it so that you retain a clean copy of the original data.
Another useful resource supplied with Visual FoxPro is the Solutions application:
The Solutions application consists of perhaps a hundred small forms and programs which
demonstrate useful techniques. These are supplied with their complete source code and a
dedicated help file to explain the techniques that have been used. Select Do from the Program
menu then navigate to the C:\Program Files\Microsoft Visual FoxPro 9\Samples\Solution folder
and run Solutions.App.
Early versions of Visual FoxPro shipped as part of the Visual Studio suite and with these you
will find the application in the MSDN folder.
where the date is inserted automatically and the cursor is positioned one space to the right of the
'*--' on the first line, ready for me to type my comments into the program. It's a big help when
I'm editing other people's code. I've always known that I ought to be commenting my changes
and I do it a lot more now that it's so easy.
Select the Custom tab and type a new abbreviation - in this example I've used CB for 'Changed
By'.
Click the Script button and what looks like a procedure-editing window will open.
Write this code in the window:
LPARAMETER oFoxCode
LOCAL lcDate
&& System date as a string.
LOCAL lcComment
&& The text to be inserted.
lcDate = DTOC(DATE())
IF oFoxCode.Location = 1
*-- We're editing a program so make the substitution.
*-- The tilde marks where the insertion point will be.
*-- Note that there's a space after the tilde.
*-- The expression inside the <<double chevrons>>
*-- will be evaluated.
oFoxcode.valuetype = 'V'
TEXT TO lcComment TEXTMERGE NOSHOW
*-- ~
*-- Geoff Franklin - <<lcDate>>
ENDTEXT
ELSE
*-- We're not editing so return the keystrokes unchanged
lcComment = oFoxCode.Abbrev
ENDIF
RETURN lcComment
Save your changes by closing the edit window and the IntelliSense Manager.
Open a program edit window and test the new entry by typing CB. You should see the 'CB'
disappear and be replaced by the comments.
If it does not work, open the IntelliSense Manager and make sure that Enable IntelliSense is
ticked on the General tab.
Debugging a script is difficult. You can insert Set Step On into the code to open the debug
window and suspend execution but you cannot Resume again. The best way of debugging is to
go back to the old technique of adding DebugOut statements at crucial points.
Note that this piece of code used FoxPro's text merge commands.
Other uses
I've also modified the IntelliSense table entries to help me write HTML. I'm writing this page
now in VFP 7 and I've just inserted a pair of paragraph tags:
<p>
|
</p>
by typing the two-character code PP. This inserts the tags then moves up a line and two spaces
across so that my text will be nicely formatted.
FoxPro TextMerge
You can use the Copy To command to create a simple text file from a table with various forms of
delimiter between fields. The TextMerge commands let you create a more complex text file. The
contents can be a mixture of plain text, fields and variables, and FoxPro functions.
The commands are:
Set Textmerge On
Tell FoxPro to evaluate all the text it sees between the double chevron delimiters << and >>. If
necessary, these delimiters can be changed with the Set Delimiters To command.
Set Textmerge To <filename> Noshow
Direct the output to a file. The file will be created if it does not already exist. If the file does exist
and Safety is On then you will be asked whether you want to overwrite it. The Noshow clause
suppresses output to the screen and is useful if this command is being used in an application.
\xyz
Send the characters 'xyz' to the file. The characters are preceded by a carriage return/linefeed
combination. There is no need for quotes around the characters. If you put quotes around the
characters then the quotes will be output as well.
\\xyz
Evaluate the FoxPro expression. The expression can be the name of a field or memory variable
or a FoxPro function. The example below shows how you can mix <<foxpro expression>> with
plain text on the same line.
This short program will produce a text file named 'customer.htm' which looks like this in a
browser:
This is a very simple page but even so the mixture of TextMerge and HTML can be confusing to
write. Both use the < and > symbols and it's easy to get confused. TextMerge is however a very
powerful and flexible technique which lets you build a page which will display a mixture of text
and data.
Visual FoxPro offers other ways of generating HTML. These are described on the HTML from
FoxPro page.
Gotcha
There are two things to watch out for when using text merge and a third when using it to produce
HTML:
Everything on the line after a \ or \\, including any trailing spaces, will be output.
The carriage return/linefeed comes before the characters are output.
Remember that a \\ produces a new line of output in the text of the HTML file. It will not
produce a new line on the web page. You never really need to use a \\ when generating HTML
because browsers ignore new lines in the HTML source.
Scope
The SCAN command can take a scope clause if you need to produce a file based on a particular
set of records. More details on the scope of Visual FoxPro commands here.
Destructive commands like Delete and Replace which default to the current record only.
Benign commands like Locate and Sum which default to the entire table.
This makes sense. If you make a mistake with a command like Delete then it's reassuring to
know that the damage has been limited to the current record and it won't be too much work to put
it right.
Most of these commands can take additional clauses to give you fine control over the records
that are going to be processed. There are 6 keywords:
All
For <logical expression>
Next <numeric expression>
Record <numeric expression>
Rest
While <logical expression>
These are described below but note that all of them will respect any filter so "all" in the next
section means "all the records available to the current filter."
All
As has been mentioned above, this is the default scope for many of the non-destructive
commands. It can however be applied to any of the others so for example:
Delete All
will delete all records which have "Bath" in the City field.
The criterion for equality is controlled by the state of the Set Exact flag.
will send the contents of the next 50 records to the printer, "next 50" meaning the next 50 records
according to the current index order. If no index order is in effect then the command will apply
to the next 50 record numbers.
The Next clause can be very useful for this sort of interactive usage but if you see it being used
in an application then you're usually looking at an old design with no relational features. It used
to be used where you would always have a block of ten records for each order because these held
details of the ten items that were permitted for each order. A better design would of course have
the item details in a separate table so that there could be any number of lines per order.
This syntax is supported by Visual FoxPro 9 but is not to be recommended. Nobody reading this
line will have any idea why record 3 is important.
Rest
Rest is another clause which relies on the position of the record pointer and on the order of the
records but this one can be very useful when you are tuning an algorithm for speed. If you can
arrange the records so that they are in a certain order then you might be able to design the
algorithm so that you can just process all the records from a certain point in the table:
Copy Rest to Customer.xls Type Xls
will copy all the records from the current position - including the current record - to an Excel
spreadsheet. This can be much faster than working through the entire set of records, picking and
choosing as you go.
If you don't need the current record then use the Skip command to move to the next record
before processing the "rest".
This code will put the table into City order and then move the record pointer to the first record
for "Bath". Because the table is in City order we know that all the records for "Bath" will be in a
block following the current record and the While clause makes sure that we will process that
block of records and no more. If we had used a For here then the application would have
continued retrieving and examining the rest of the records in the table.
Careful use of While can reduce the running time of an algorithm from order n 2 to order n. If
you are processing all the deliveries for all the customers then a simple design would be to scan
the entire deliveries table once for each of the customers. By using While you can process the
deliveries for the first customer and then carry on from that point to process the deliveries for all
the following customers one at a time. This just takes one scan through the customer table and
one through the deliveries table.
As with the for clause, the definition of equality is controlled by the state of the Set Exact flag.
Exact matches
The way that the For and While clauses match records for equality
is controlled by the state of the Set Exact flag. This has a global value across the current data
session and can take either of the two string values "ON" and "OFF"
If Exact is "OFF" then two strings will be considered equal if the first letters of the longer string
match all the letters of the shorter string. The command:
Locate For Town = "Bath"
will find "Bath", "Bathavon", "Batheaston", etc. If Exact is "ON" then it will only find the exact
match of "Bath".
The default behaviour can be set by selecting Options from the Tools menu and picking the Data
tag.
Use the following commands to alter the state of Set Exact whilst a program is running:
Set Exact "On"
Set Exact "Off"
It is always a wise precaution to have one of these commands at the head of your program. This
ensures that, regardless of any local settings, you can be certain that your application will be
operating with exact or partial matches as appropriate. You will also need to repeat these
commands whenever you start a form with a private data session. The value of Set Exact is
restricted to the current data session.
Note that Set Exact only applies to string comparison using a single = operator. If the
comparison uses the double == operator then the two strings will only be considered equal if
they are the same length and any trailing spaces will be included in the comparison.
Set ANSI
Set Exact applies to the native FoxPro commands and not to records being selected by SQL
commands. The screenshot above shows that Set ANSI has also been set to "ON". This has a
similar effect on comparisons in SQL.
This snippet of code will export all the fields of the current table into a text file with commas
between each field and with each record on a new line.
are typical of the syntax of a comma delimited file. There are two fields in the table and each
record has its two values on a separate line.
There is a comma between each data value but you've probably taken the double quotes around
the names for granted because that's something of a standard in the PC world. The danger is that
we often have to use a csv file when we're sharing data with other computer systems and people
working on other operating systems might have a different understanding of the term "comma
delimited". They might say that that the output here was separated by commas but that each
string value was delimited by double quotes. You're unlikely to have any confusion when you're
talking about commas and quotes but if someone asks you to create a file delimited with
underscores or pipes then you really do need to see a sample so that you're sure that you
understand what is needed.
Note that it's only the string values which have delimiters. Numeric and date values stand alone.
Don't put braces around date values because that's FoxPro syntax. Access for example expects a
# character either side of a date.
Other delimiters
The extended syntax of the Copy To command starts by following one of these conventions for
the meaning of "delimiter" but then contradicts itself. For example, if we specify a dollar sign as
the delimiter:
Copy To Town.txt Type Delimited with $
then this command will produce a text file having the following structure:
1,$Alvechurch$
2,$Bromsgrove$
3,$Catshill$
4,$Dudley$
It's obvious that Fox is taking "delimited" to mean the characters marking the strings here. Three
further forms of the command take the opposite meaning and take "delimiter" to mean the
separator between fields:
Copy To Town.txt Type Delimited with Tab
Copy To Town.txt Type Delimited with Blank
Copy To Town.txt Type Delimited with Character _
These three commands will produce text fields with tabs, spaces and underscores between the
fields respectively. All of them retain double quotes as delimiters around the strings:
1
2
3
4
"Alvechurch"
"Bromsgrove"
"Catshill"
"Dudley"
1 "Alvechurch"
2 "Bromsgrove"
3 "Catshill"
4 "Dudley"
1_"Alvechurch"
2_"Bromsgrove"
3_"Catshill"
4_"Dudley"
Finally, we can mix the two terminologies and specify two different "delimiters", one between
the fields and another around the strings:
Copy To Town.txt Type Delimited With $ With Character _
This will give us underscores between the fields and dollar symbols around each string:
1_$Alvechurch$
2_$Bromsgrove$
3_$Catshill$
4_$Dudley$
It might look a little confusing but with a bit of experimentation you should find that you can
match most formats used to export data as plain text.
If the Town ID fields are four characters long and the Town Names are 15 characters long then
this example will generate:
1...Alvechurch.....
2...Bromsgrove.....
3...Catshill.......
4...Dudley.........
In this example the spaces have been shown as '.' for clarity and the paragraph markers have been
displayed.
This gives us a memo field of plain text but still leaves us with the problem that the the Copy To
command will not process a memo field. The solution again is to use the TextMerge function
inside a scan loop.
If you do have to create a csv file which includes memo fields then you must talk to the person
who'll be receiving and processing the file. They too are going to have to do some preprocessing
before they can import your data into their application and they might have restrictions which
make the whole process impossible. For example, the FoxPro memo field might be holding more
text than their import routine can accept.