Session E-WIZZ

The Builder Builder's Reference

Steven M. Black
SBC / UP!


Introduction

Great news from VFP comes from how the Class Designer (cd) and the Form Designer (fd) interact with the development environment. All Visual FoxPro objects are endowed with both design-time and run-time manifestations and public interfaces.

Custom programs, written in FoxPro, can manipulate our design-time work. For the first time support for this sort of thing is built into the language. And it's extensible, because the architecture is open. This has really profound implications.

Here is the definition of "Builders" as found in the Visual FoxPro Help file:

That seems rather limited.

Here is the definition of "Wizards", taken from the same source:

These definitions suggest that Builders and Wizards are friendly interactive things, dialogs really, that set properties and generally get things started or done. More importantly, the simple task-oriented tone of that definition is good for marketing folks who can easily understand and demonstrate such things.

Here is a wider, more developer-centric definition:

This wider definition recognizes that, sure, Builders and Wizards can be cute dialog-based programs that set properties. But they also can add, audit, backup, build, compile, delete, document, edit, find, harmonize, localize, maintain, merge, reference, restore, substitute, transform, update, validate, write... whatever. Invisibly or otherwise. Builders open a door — a big door, a door so wide you could drive a Mack truck through it! There's little in Visual FoxPro that cannot be done with a custom Builder.

This document serves as an evolving reference for creating Builders and Wizards. Everywhere herein "Builders" are mentioned also applies to Wizards because, in my understanding, Wizards are a form of Builder.

This cannot possibly pretend to be a complete treatment of Builders and Wizards. Builders, as I have defined them, are a wide and diverse subject. In the coming years we will see some remarkable software engineering, some of it occurring through the application of Builders. My goal right now is to make developing Builders and Wizards easier.


This Builder and Wizard Reference

If you think about it, we've had Builders for a long time. FoxPro 2.6 was the first version to ship with Wizards. The Flash Development Toolkit, to take another example, is chock full of individual Builders for FoxPro 2.x (and which, for the most part, work unchanged in VFP). FoxExpress is a cool Wizard if ever there was. GENSCRNX and its variants and add-ins (like 3D.PRG) are all Builders, though we never called them that before.

This document is organized into an alphabetic presentation of helpful things to consider when building your own Builders and Wizards in Visual FoxPro. At first glance the sequencing doesn't seem very imaginative. Hopefully you will feel differently when you need this more for reference and not intending to make this a sequential read.

From here forward, unless otherwise specified, "Builders" means "Builders and Wizards".

Like _GENMENU, _GENGRAPH, _BROWSER and the others, _BUILDER is a system memory variable used to point to a Builder application. The value of _BUILDER defaults to HOME()+"WIZARDS\BUILDER.APP". You can set the default _BUILDER in the File Locations page of the Tools-Options dialog or in CONFIG.FPW.

If you use Windows NT, this and all other kindred configuration information is kept in the NT registry under HKEY_CURRENT_USER|Software|Microsoft|VisualFoxPro|3.0|Options. The registry entry will be overridden by any valid _BUILDER setting in CONFIG.FPW, and as always, you can interactively change the _BUILDER system memory variable from the command window. See also the BUILDER.APP, Native Builders, and _WIZARD topics below.

You may, as always, substitute your own Builder manager for the native BUILDER.APP. We may soon see a BUILDERX in the near future. Stay tuned, and remember that word of great Builders will likely appear in CompuServe's FoxUser forum months before you'll read of them in magazines.

Like _BUILDER, this is a system memory variable used to point to a Wizard application. The value of _BUILDER defaults to HOME()+"WIZARDS\WIZARD.APP". Like for _BUILDER, you may assign any program to act as your Wizard application.

Everything you can do interactively with the Command Window is doable with Builders. Here are broad categories of things you can't modify with FoxPro code.

Class Hierarchy Properties, which are: Baseclass, Class, Classlibrary, OLEclass, and Parentclass. To change an object's class you need to either substitute a new object having the correct pedigree, or alternatively close the fd and open and change the underlying SCX. There is no way to reconfigure class pointers of in-situ objects because they are fullblown live objects, even when seemingly just displayed by the design tools.

Control Array Assignments like the Buttons, Columns, Controls, Forms, and Pages properties cannot be modified at design-time. The control array index sequence is a function of the Z-order, and the length of the control array is determined by the number of instantiated objects.

Object Count Properties, like Controlcount, Formcount, and Listcount, are a read-only and determined by the number of objects present.

The Program Status Properties include Activecolumn, Activeform, Activerow, Activecontrol, Docked, Dockposition, Formindex, Itemdata, Itemiddata, List, Listindex, Listitem, Listitemid, Relativecolumn, Relativerow, Selected, Sellength, Selstart, Seltext, Topindex, and Topitemid. These properties have no tangible meaning at design-time and cannot be set by Builders.

Builders can add objects to containers. For example, executing the following code will add a Label named lblHello and a Commandbutton named cmdQuit to a Form in the fd session:

AMEMBERS() is useful for determining all sorts of information about objects and what objects and members they contain. Keep in mind that it's possible to make properties and methods PROTECTED, which hides them. A Builder cannot affect protected properties and methods, so you should check for the visibility of properties and methods before attempting to modify them.

Description: Creates or updates an array of properties, procedures, and member object names, and returns the number of rows in the array.

Parameters:

For an applied example using AMEMBERS(), see Drilling down below.

A weakness in the fd and cd interfaces is that array member properties cannot be changed in the Properties Sheet. Builders, on the other hand, may change the contents of array member properties, but cannot change the DIMENSION of member arrays.

One way to change the DIMENSION of a member array property is to remove and recreate the array property. The other is to edit the SCX or VCX directly. See the last part of the Reset to Default (properties) and Custom members topics for information on how to do this.

This gets my vote as one of the best new functions in Visual FoxPro. It is wonderfully functional, and sparse as it is, I can think of no enhancements to suggest for it.

Description: Creates or updates an array of object references to currently selected controls in the active fd, and returns the number of rows in the array.

Parameters:

ASELOBJ() is perhaps the most useful function when using Builders. Here is a table of ASELOBJ() examples:

 
Task Code Comments
To reference currently selected object =ASELOBJ( MyArray)  
To reference all currently selected objects =ASELOBJ( MyArray) Contents in Z-order Sequence
To reference object's container =ASELOBJ( MyArray,1)  
To reference the form =ASELOBJ( MyArray,1)
DO WHILE MyArray[1].BASECLASS<>"Form"
MyArray[1]=MyArray[1].Parent
ENDDO
 
To reference the Formset =ASELOBJ( MyArray,1)
DO WHILE MyArray[1].BASECLASS<>"Formset"
MyArray[1]=MyArray[1].Parent
ENDDO
 
To reference the DataEnvironment =ASELOBJ( MyArray,2)  

If you add a Builder property to your class, BUILDER.APP will recognize this, and invoke the builder specified there. This means that you can assign a specific Builder to work with the objects you create from classes.

If the Builder program specified by the object's Builder property is missing or invalid, BUILDER.APP generates a friendly warning, then the usual BUILDER.APP program executes, which is as graceful a recovery as one could expect.

A disadvantage of using a Builder property: BUILDER.APP executes this Builder without ever presenting a picklist of other registered Builders that may apply. The Builder property is interpreted by BUILDER.APP as an exclusive Builder, which is regrettable. See BUILDER.APP and BUILDER.DBF below.

The BUILDER.APP that comes with FoxPro is not a Builder, but rather a Builder manager. Its function is to take stock of the situation, invoke (or present a choice of) the appropriate Builder program, and return you cleanly to the FoxPro design environment. BUILDER.APP is a modal application. The source code for BUILDER.APP and all the native Builders is not included in VFP.

After working for several weeks with Builders, I find myself working around it more than with it.

The Builder registration table, BUILDER.DBF, lives in HOME()+"WIZARDS" directory. VFP's standard BUILDER.APP checks this table for Builders of a particular type. If more than one record of the same type is present, a picklist is presented to you. Otherwise the program specified in the Program field is invoked without fanfare.

BUILDER.APP does not provide services for registering and unregistering Builders in BUILDER.DBF. You must maintain registration records interactively. If BUILDER.DBF is missing, BUILDER.APP will recreate the standard BUILDER.DBF.

Tip: Using the Form Wizard, create a BUILDER.DBF viewer, then register it as a Type="ALL" builder. You can then use any convenient Builder hook to manage the behavior of BUILDER.APP. For more details, see Registering Builders and WIZARD.APP.

The structure of BUILDER.DBF is exactly that of WIZARD.DBF.

 
Field Name Type Description
NAME C-45 Name of the Builder. This appears in the picklist displayed by the standard BUILDER.APP when there is more than one Builder for this class of object.
DESCRIPT M-4 Long description for the Builder. This is also displayed by the standard BUILDER.APP when there is more than one Builder for this class of object.
BITMAP M-4 Not currently used by builders.
TYPE C-20 Contains a keyword, such as a FoxPro Baseclass name, "ALL", or some other moniker that identifies the type of Builder or the context in which it is to be called.

Note: The algorithm used by BUILDER.APP to determine the Type is not public, not data-driven, and cannot be changed. This, above all else, makes BUILDER.APP difficult to work with.

PROGRAM M-4 The program to invoke.
CLASSLIB M-4 The class library that contains the Builder (if in a VCX).
CLASSNAME M-4 name of the class of the Builder.
PARMS M-4 Parameters to pass to the PROGRAM.

Visual FoxPro comes with many Wizards and Builders. Most other Microsoft products come with only Wizards. Why the difference? It's due mainly to a change in parlance at Microsoft. A rule to distinguish between them: If it gets you started it's a Wizard, otherwise it's a Builder.

In my parlance, a Wizard is a specific type of Builder. So my rule is different: Assume something is a Builder, and if it gets you started on something, then it is also a Wizard.

Builders and Wizards are very similar. For example, the Registration tables (BUILDER.DBF and WIZARD.DBF) are identical in structure, though some fields are used by Wizards but not by the native Builders. As you would hope, the native Builders and Wizards are written in FoxPro, and they reportedly share some code, and they share some elements of WIZSTYLE.VCX.

A design-time method, applicable to most types of controls, that creates an exact duplicate of an object in its current container. Useful for, among other things, creating backups before your Builders run amok. See the Undo topic below.

The clone is such that all properties (including Top, Left, Width...) are identical. Therefore you can't tell you created a clone just by looking at it; you need to move the clone in order to see both the clone and the original.

One would think, given VFP's automatic object naming abilities, that the NewName parameter would be optional. It isn't.

Control classes hide all the details of their members unless you are working in the cd. So Builders launched from the fd cannot penetrate Control classes.

When working in the fd, only Form objects can accept custom properties and methods. When in the cd, only the "background" object can accept custom properties and methods. To convince yourself of this, open a CommandGroup in the cd, add try to add a custom property to one of the CommandButtons. It can't be done.

In any event, how to add properties and methods to Forms in the fd or to classes in the cd? In Visual FoxPro 3.0, KEYBOARD stuffing using the Form or Class menu seems to be the only way. The following function can be used by Builders to programmatically add custom members.

You can create a Dataenvironment reference (and influence the Cursor and Relation objects therein) by using 2 as the second parameter in ASELOBJ(). For example:

Drill-down Builders act on an object and, if the object is a container, then acts on the objects that may be contained therein. Implication: forget the notion that Builders should work only on selected objects.

Visual FoxPro comes with a handy SetAll() function for setting properties (see the SetAll topic below), but there are times when you need better control than SetAll() can give.

Drill-downs are useful when we need to affect everything, at whatever the level, in a container. For example, a Builder to change the Fontsize on all objects in a Form could ignore the selected objects and work directly with the Form and all its contents. A Builder that enforces standards and guidelines might be expected to audit an entire Form, and not be limited to what controls happen to be selected.

There are a variety of ways of structuring a drill-down, all employing one or more of the following steps:

For example, here is a trick-or-treat Builder that makes everything in a container a random color. Note the variant: if an object is not selected (perhaps the Builder is invoked from the command window) then the Builder acts on everything. See also Pageframes and pages.

The error handling you need still depends on your tolerance for pain, but Builders present a special challenge. We are all accustomed to treading carefully with data. Now we must do the same with source structures, because that's what Builder programs modify! GENSCRNX users have often found comfort in knowing that all changes are made on temporary structures. This isn't true in VFP with BUILDER.APP.

At this time I don't have specific recommendations to make with regard to errors and Builders, other than to point out that, as usual, a clumsy error without a backup can ruin your day.

In this release of Visual FoxPro, there is no way to group screen objects as we would in FoxPro 2.6. Fortunately, ASELOBJ() can distinguish if multiple objects are selected, and will create an array of object references, one for each selected object. So unlike the Properties Sheet, Builders can act on multiple objects.

There are seven or more ways to invoke Builders, five of which are standard hooks from within FoxPro.

I won't dwell on the first five items in this list. These are sufficiently documented in Help, the VFP manuals, and already in many articles.

Invoking Builders from custom toolbars is an intuitive approach to managing builders. Mechanisms for calling your various builders from within click events of toolbar controls is easy to set up. A nice variant: create a _SCREEN.Timer as a voyeur class that reacts to the activation and deactivation of the fd by showing and hiding the appropriate toolbars, including your builder toolbar.

Browser drag and drop builders are created by placing Builder code in the Init of sacrificial builder classes stored in VCX or SCX structures, with the Init ultimately returning .F. so no object is created. Presto: To run a builder, drag its class from Browser to the desktop. The Init code fires (which runs the builder) and returns false. A variant: Several builders can be combined into a container. The Builder elements execute in Z-order.

You may invoke a Wizard programmatically with

This brings forth a selection dialog containing all the Wizards registered in WIZARD.DBF. You can bypass this dialog

In this case, since more than one Wizard exists for this situation — VFP ships with both a Form and One-to-Many Form Wizard — the selection dialog is presented, and its list contains just the two Form Wizards. If only one Wizard of Type="FORM" existed, there's no selection dialog, and the wizard would be launched directly.

To explicitly run a given Wizard, specify the Wizard name or class in the second parameter.

The mechanism with the second parameter is as follows: By default the Program field in WIZARD.DBF is searched for the second parameter. If nothing is found, then the Classname field is searched.

WIZARD.APP passes through up to seven additional parameters to the selected wizard program.

DO (_WIZARD) WITH SomeType, WizardName, Param3,... Param9)

Visual FoxPro lists the following Builders in BUILDER.DBF.
Builder Description
Edit Box Builder Creates and sets properties for an edit box control.
Option Group Builder Creates and sets properties for buttons in an option group.
List Box Builder Creates and sets properties for a list box control.
Grid Builder Creates and sets properties for a grid control.
Form Builder Adds controls to a form using fields and a style the user specifies.
Combo Box Builder Creates and sets properties for a combo box control.
Command Group Builder Creates and sets properties for buttons in a command group.
AutoFormat Builder Applies a style to selected controls on a form.
Referential Integrity Builder Creates triggers and stored procedures that enforce referential integrity between tables in your database.
Text Box Builder Creates and sets properties for a text box control.
AutoFormat Builder Applies a style to selected controls on a form.

Visual FoxPro lists the following Builders in WIZARD.DBF. (v ) indicates an improved Wizard over the 2.6 version. (Õ ) indicates that this Wizard is included in the Professional Version only
Wizard Description
Form v  Creates a form based on a single table
One-To-Many Form Creates a 1-Many form with a grid control for child table
Report v  Creates a report based on a single table
Group / Total Report v  Creates a report with groupings and totals
One-To-Many Report v  Creates a 1-Many report
Label v  Creates a mailing label report based on pre-defined styles
Import v  Imports a foreign file format to a FoxPro table
Documenting Õ  v  Documents and formats FoxPro source files
Table v  Creates a new table
Local View Creates a view using local data
Remote View Creates a view using remote data
Query v  Creates a standard query
Graph v  Creates a new graph using MS Graph
Cross Tab v  Creates a new cross tab table based on existing data
Pivot Table Creates an Excel PivotTable based on FoxPro data
Mail Merge v  Creates a Word Mail Merge document based on FoxPro data
Upsizing Õ  Moves FoxPro data files to SQL Server files
Setup Õ  Creates installation program for distribution of custom apps

Builder programs can be modal or modeless. The native BUILDER.APP and WIZARD.APP are modal, but that's not to say that your custom Builders and Wizards should be. Modeless programs are more susceptible to unforeseen problems brought on by external factors. This can be reason enough to eschew modelessness. But needlessly modal programs can be a pain to use. You must decide this issue based on what factors balance best for you.

Builders can act on multiple objects as selected in the Form or Class Designer. ASELOBJ( MyArray) can be used to populate MyArray with object references. The sequence of pre-selection is irrelevant, and the array is sequenced in object Z-order.

Native builders include an AutoFormat Builder, which you will see if you invoke FoxPro's standard BUILDER.APP while many objects are selected.

After creating a few Builders, some common 'workaround' themes emerge. One of these themes results from the incongruous nature of Grids and Pageframes compared to other sorts of containers. Whereas all other containers can contain controls, Grids can only contain Columns, and Pageframes can only contain pages.

This means that Pageframes and Grids do not have Controlcount and Controls[i] properties. Drill-down routines cannot therefore rely on the existence of Controlcount property to determine if a given object is a container. Similarly, you cannot assume that members of container objects possess Top and Left properties, or can even GetFocus().

This explains why the drill-down routine in the Drilling down topic uses the slower but consistent AMEMBERS(,,2) to determine if a given object is a container and, if so, what it contains.

VFP passes two parameters to the program designated by _BUILDER. The first parameter is a 1-D array of selected object references (see the ASELOBJ() topic), and the second parameter varies according to how the Builder was invoked, as in the following table:
Invocation Second Parameter passed by standard BUILDER.APP
Builder Lock on the Form Controls toolbar "TOOLBOX"
Property Sheet button "PSHEET"
RIGHTMOUSE pop-up menu. "RTMOUSE"
Form Design Toolbar "QFORM"
Manual invocation Whatever you pass upon invocation

If _BUILDER is set to BUILDER.APP, then BUILDER.APP passes three character type parameters to registered Builders.

The first parameter is the string "wbReturnValue", which is puzzling unless you know the following: Sometimes BUILDER.APP or WIZARD.APP need to return a value to the calling routine. Fine, except that someone decided that Builders and Wizards should not be called as procedures or functions (something I do all the time!). "WbReturnValue" is the name of a memvar created by BUILDER.APP and WIZARD.APP that should be updated with the return value. In practice you'll probably never need to know this fact.

"Para1, Para2, Para3..." or, more precisely, whatever is contained in the PARMS field of WIZARD.DBF or BUILDER.DBF. You may use this string as you please. Most basic custom Builders called by BUILDER.APP will really only use this parameter.

M.wbcpOptions, the third parameter, contains the keyword information that may have been passed into BUILDER.APP (see the table in the previous section). Also added to this string are any other parameters that were received in the placeholder parameter slots, separated by spaces.

It may be helpful to know that so far I've never needed to use the parameters passed to builders. ASELOBJ() can typically tell us everything we need to know.

In most cases, VFP passes a single parameter to _WIZARD, a string to look-up in the TYPE field of WIZARD.DBF. If the _WIZARD is invoked from the Project Manager, then three parameters are passed: 1) A string to look-up in the TYPE field of WIZARD.DBF, 2) a string of length zero, and 3) the string "NOTASK".

Visual FoxPro's native WIZARD.APP passes nine parameters to its Wizards.

Parameter1: Reference to a variable containing the name if the Wizard generated file. This memory variable gets passed back to VFP when the Wizard is finished. This is so other resources, the Project Manager for example, can be refreshed upon return from a Wizard launched there.

Parameter2: This parameter is the contents of the Parms field in the Wizard registration table.

Parameter3 - Parameter9: These are extra parameters passed to _WIZARD. They are optional parameters which are not used by the standard shipping Wizards, but can be used by your custom Wizards.

Implications for Wizard writers:

The native BUILDER.APP program that ships with VFP relies on the BUILDER.DBF table that lives in the VFP Wizards directory. To register a Builder is to manually add a record in this table. The native BUILDER.APP offers no services to transact with BUILDER.DBF. See the BUILDER.DBF topic.

Here is an easy way to give a registration interface to BUILDER.APP:

Field Entry
Name BUILDER.DBF maintenance
Descript Edit BUILDER.DBF
Type All
Program BldrUtil.PRG

 

Now you can converse with BUILDER.DBF just by launching BUILDER.APP since the "All" builder type is, as you might expect, universal.

Unconvinced of the power of Builders? Then note that Relational Integrity in Visual FoxPro is enforced by code written by a Builder. Not too shabby for power, I'd say. To convince yourself of all this, invoke and run the RI Builder from the Database Designer (DD) with a right mouse click. Then look at the Stored Procedures, also available through a right mouse click on the DD. All that delineated code was written by the RI builder (See the WRITEEXPRESSION() and WRITEMETHOD() topics below).

This means that, among other things, if you don't like FoxPro's implementation of Referential Integrity, then you can wrapper the current RI builder, or even create your own.

A helpful hint if you wrapper any builder: When multiple copies of a function are found in the same FoxPro source file, the last one always gets executed. This means that you can append code to the RI code in the Stored Procedures, and your versions of duplicated functions will execute.

Description: Design-time method that returns the expression stored to a property. To write expressions to properties, use WriteExpression().

Parameters:

Example:

As shown, it is possible to store an expression to a property and have ReadExpression() return blank. This is not a bug. When we say oForm[1].Caption= CDOW(DATE()), we are storing the value of CDOW(DATE()) to the Caption property. To store an expression to a property, use WriteExpression().

Description: Design-time method that returns method code as text. Use ReadMethod() to reckon the code (if any) in an object code snippet.

Parameters:

All the code in the specified method is returned as a string with embedded character returns, tabs, comments, and whatever else is in your code.

When the cursor is on the properties section of the Properties Sheet, RIGHTMOUSE invokes a popup menu that contains, among other things, a "Reset to Default" pad that restores the Parentclass's properties, events, and methods.

To reset events and methods to default, use WRITEMETHOD() to set the snippet to an empty string. For example, to reset the INIT of the currently selected object:

Resetting properties to default cannot be done directly — there is no command or straightforward mechanism to do this.

One indirect way is to instantiate a dummy object and poll its property values. Doing this doesn't really "Reset to Default" since you won't be inheriting; the default value is hard-coded and happens to be, for now, equal to that of the default.

If you are intrepid, a Builder can always release the SCX, USE the SCX, navigate to the correct record, delete the appropriate lines in the Properties memo, close the SCX, issue a COMPILE FORM ..., then re-open the SCX again. It isn't pretty— for one thing there is currently no way to 'reselect' the originally selected objects — but it otherwise works.

Description: Design-time or runtime function that saves a .VCX-based Form or Formset as an .SCX.

Parameters:

Example uses: You could use the SaveAs method to store all the PEMs associated with an object to another .SCX file. Also you can CREATEOBJECT() an object or even a whole form, customize it from the command window, and use .SaveAs() to programmatically save it for future use. See the Undo topic below for another example.

Description: Design-time or run-time method that saves any .VCX/SCX based class (except Dataenvironment, Page, Column, and Header) in a class library.

Parameters:

Here's an interesting thing about SaveAsClass: as long as the class is VCX-based, then programmatic class transformations can happen and SaveAsClass() will work downstream. This is useful for importing classes developed in code into a VCX. Example:

Description: Assigns a property setting on all, or a certain class of, controls in a Container object.

Parameters

Very useful and powerful! See also the Drilling down topic.

A bummer: If you issue a SetAll() for a user-defined (i.e. a non baseclass) class that isn't instantiated or doesn't otherwise exist, VFP generates error 1733, "Class definition ClassName not found".

Builders are an excellent way to learn the minutia of Visual FoxPro controls. Puzzled about how to create a Grid with a given look or behavior? Use the Grid Builder to construct something similar, then reverse-engineer it.

In the end, you will be better off with a sensible class hierarchy and reusing your designs rather than relying on Builders and Wizards to repeatedly create application objects. Here's why.

If you extensively use the native VFP Wizards and Builders to create an application, then eventually you will hit a wall of maintenance difficulties. This because native Wizards and Builders use classes from WIZSTYLE.VCX, which contain some questionable points of design. Most notably:

In the end, it appears that a very shallow, or more to the point, faster class hierarchy was preferred by the VFP design team for Builders and Wizards. On balance, that's understandable.

Builders will usually make changes directly to meta data source tables. A well designed Builder will let its users abort and undo Builder processes. This means you need good state saving and restoring mechanisms. A reasonably good way to do this is use the Form.SaveAs method to make a physical backup of the screen before you start. Also consider that you can make archive copies as you go along, so allowing users to go backward one step is easily doable.

Tip: the CloneObject method may be invoked by Builders to create backup copies of individual objects. Two problems with CloneObject: Forms don't have a CloneObject method, and CloneObject makes a physical copy of the object in the current form, so you must remember to delete the backup when you're done.

Here is a skeleton for a Builder that saves the Form using the SaveAs method before doing its deed.

If you use FoxPro's native Builders, sooner or later you will wonder where they get their class information. Perhaps you want to customize these classes for your particular needs. The Classlib field of BUILDER.DBF contains many references to BUILDER.VCX, so there must be a BUILDER.VCX resource for BUILDER.APP, right? Not that you can use! BUILDER.VCX is bound inside BUILDER.APP, so you can't get to it.

This belies the wider difference between BUILDER.APP and WIZARD.APP. Operationally, all the Builders are in BUILDER.VCX (which is in BUILDER.APP), but the Wizards are in separate apps. If you browse WIZARD.DBF you will see that the Program field specifies an APP for each Wizard.

You can still replace Builders even though they are built in. If you add another grid Builder for example, you will be prompted to select what Builder you want (i.e. there will be 2 entries in BUILDER.DBF that have type of GRID). Similarly, you can delete the registration for a native builder, but cannot actually delete it since it is bound in BUILDER.APP.

Like the native BUILDER.APP, WIZARD.APP isn't a Wizard, but rather a Wizard manager. Its role is to invoke the appropriate Wizard according to the implicit or explicit conditions of its invocation.

See Also Invoking Wizards above.

The Wizard registration table, WIZARD.DBF, lives in HOME()+"WIZARDS" directory. The structure of WIZARD.DBF is as follows

 
Field Name Type Description
NAME C-45 The name of the Wizard as shown in the Wizard selection dialog.
DESCRIPT M-4 The description of the Wizard as shown in the Wizard selection dialog.
BITMAP M-4 The name and path of the bitmap which appears in the Wizard selection dialog
TYPE C-20 The wizard type
PROGRAM M-4 The program file called to invoke a specific Wizard.
CLASSLIB M-4 The VCX file containing the Wizard if a program is not provided in the Program field
CLASSNAME M-4 The class name of the Wizard if a program is not provided in the Program field.
PARMS M-4 Parameter(s) passed to Wizard APP file if needed.

 

Description: Design-time only function to write expressions to properties.

Parameters:

This function is not as straightforward as is seems because of the special way expressions are stored. VFP expects the expression expressed as a stream of characters and preceded by "=". For example, to place the current date expression in a Commandbutton, do as follows:

See also READEXPRESSION().

Description: Design-time only method that writes the specified text to the specified method.

Parameters:

Note: WRITEMETHOD( Property,"") is equivalent to "Reset to Default" for events and methods.

Strange as it seems at first, we use WRITEMETHOD to concatenate strings to build method code at design time. Use "CHR(13)" wherever you need a new line, and it's good practice to use "CHR(13)" at the beginning and end of the streams so to avoid unexpected line combinations.

This program appends code to the Form.Click event to bring-forth a "Hello World" dialog.


Conclusion

It doesn't take a genius to recognize the phenomenal potential offered to us by Builders and Wizards. The next few months will be exciting as new tools, managers, and possibly entire frameworks will be invoked and applied through Builders, Wizards, and related hooks.

From this document, the following things to retain:

  1. In VFP, there is little difference between "design-mode" and "run-mode". Objects in the Form and Class designers are "live".
  2. Custom Builders, mixed with the convenience of the native Builders, are a great way to learn FoxPro and automate software construction. Use them.
  3. Custom and native Wizards are a great way to get started on tasks.
  4. Builders are programs that help create and construct software. Therefore think of Wizards as Builders.
  5. It's okay to bypass BUILDER.APP and WIZARD.APP and invoke your own Builders and Wizards as you see fit..