Visually Impaired: Visual FoxPro for 2.6ers - ClassesRobert C. Bradley
Without a doubt, good class design is critical to a successful, easy to maintain and modify application. It is just as important as developing a good data design for a new system, and deserves at least as much thought and time. You wouldn't just start coding a system before you had laid out the tables and their relationships; likewise, class development should be completed before other work is started.
The benefits of creating and using classes far outweigh the time needed to construct them. An object created from a class inherits all the properties and abilities of that parent class. This alone makes classes the best thing since cable-ready TV.
In FoxPro 2.6, for example, you might have created a Save button that can be used on many forms. This Save button's Valid method may contain generic code such as:
You then copy and paste that button onto a dozen or two forms. Fine; but what if next week you want to add a line at the beginning that does:
M.LASTUPDATE = DATE()
Using the FoxPro 2.6 system, you'll have to go to each and every button and change that code. Accidently missed one or two? Now your "standard" Save button is no longer, as you have a mix of various versions. The same issue holds for standardizing the button's size, enabled state, and so forth.
In Visual FoxPro, you can take this same button and save it as a class; let's call it cmdSave. You then go to each of your forms and literally drop this class ("instantiate" the class as individual objects) onto the forms. The button's code exists in only one place - in the class - but is inherited by each button that is created.
Should you need to change the button's code or apearance, you need only go one place - the class - to do so.
You can also sub-class classes. Say one of your goals is a consistent user interface, and you want all your buttons to be the same size, shape, and font. You can create a cmdButton class (the parent) that has this appearance, then subclass it to the individual button classes, such as the cmdSave we just covered.
Again, that gives you one-stop-shopping point - the parent cmdButton class - where you can make modifications that will automatically be inherited by all its children.
Starting from scratch, what classes should be created as a minimum? You should subclass all of the base classes that you expect to use in any form. A "base class" is the VFP-supplied object type, such as form, label, textbox, and command button. You should immediately subclass each of these one level (let's call them BaseForm, BaseLabel, BaseTextBox, etc.).
Why go through this? Because the VFP base classes cannot, as classes, be modified. For example, if you used the base VFP label class and put that twenty times on fifteen forms, then you decided you wanted to increase the font size by a point, you'd have to go to each and every label to make the change. Yuck-city. By subclassing them into a user-created class that will reside in a class library (VCX), you gain complete control over them.
CLASS LIBRARY FILES (VCX)
There are no rules on how you store your classes. They must be stored in one or more class library files (VCXs), but whether you put them all in one or break them into separate ones depends a lot on team size, size of the project, and other factors.
REAL LIFE EXAMPLES
Create the "base" classes as described above, and save them in a class libary called "base.vcx".
Now let's create a new, blank class library called IPTM; in it we will store our high-level classes that we might use across projects:
CREATE CLASSLIB IPTM
Crank up the Class Browser by going to VFP's Tools, Class Browser menu option. When it pops up, click the Open icon and choose your IPTM.VCX class library.
Click the New Class icon (see the tooltip text), enter "dataform" for the Class Name, for the Based On click on the [...] and choose your BASE.VCX in the left panel, and BaseForm in the right, and the Store In should be IPTM.VCX.
You have created a new form class called DataForm that is a subclass of your BaseForm, which itself is a subclass of the VFP-base Form class. Let's pretend that we will use this form as the base for our standard data-entry type activity.
What are some things we want for every data-entry form? Well, we might want a nice paper-like bitmap as our wallpaper. We might want to turn on ShowTips.
It is also the perfect place to put code ("methods") that can be used by any data-entry form. For example, we might want to be able print the current record, so we can create a PrintForm method at the class level, and all forms based on it can call that one routine.
But wait a minute, you say! I could do the same thing by creating a PrintForm.Prg or a procedure within a larger PRG library. That is true, and in reality you would get equivalent results. But...one of the principles of object oriented programming (OOP) is "encapsulation": the ability of an object to be self-contained and self-reliant. By putting the code within the form for use by the form, we have encapsulated that behavior. A benefit, one might argue, is that if you wanted to copy your form behavior to another system, you could simply copy the class; whereas in the PRG approach, you would have to also copy that PRG (and any others created the same way).
Double-click our DataForm class to edit it (from the command line, you can use the MODIFY CLASS command). When it comes up, click the Class menu, then New Property; call that property PrintFRX. Now back to the Class menu and choose New Method; call that method PrintForm.
Within the PrintForm method, we'll put in some code like:
IF NOT EMPTY(THISFORM.PRINTFRX)
REPORT FORM PRINTFRX NEXT 1 TO PRINT PROMPT
Now, when we create individual instances of this form, we simply fill in the PrintFRX property for each as appropriate. We can add a Print button to the form whose Click method says:
To create an actual form from a class, there are several ways to do it, but I prefer the command window way:
CREATE FORM PEOPLE AS DATAFORM FROM IPTM
We should also create a subclass of our BaseCommand class and call it cmdSave (use the Class Browser's New Class button like we did for the DataForm class). In this cmdSave class's Click method, we can put in whatever code would be approriate in the majority of the cases (code can be overwritten on subclasses or on the individual object level).
Then, assuming we want every data-entry form to have a Save button, we can drop this cmdSave class onto the form, and it will automatically appear on every form based on it. To drop the class on the form, the easiest way is to click the "library books" button in the standard VFP toolbar, select Add, and choose your VCX file (IPTM.VCX). An icon will then appear for each class you have there.
This is just the tip of the iceberg for classes. If you haven't used them before, it can seem overwhelming. But once you've done it thrice, it is simple and quick.