Session E-CLASS

Building Applications
Using Class Libraries

Toni M. Taylor-Feltman
Neon Software


Overview

At the heart of Object Oriented Programming are class libraries. Class libraries are the building blocks of all object oriented applications. Visual FoxPro’s class designer gives developers the tool necessary to create these "building blocks." Creating applications from class libraries results in more easily maintained applications.

This session focuses on how class libraries will help us create better applications, faster. Class libraries are more than just a group of objects that are dropped on a form. They are the nucleus of all applications. We will explore how to design reusable class libraries that can be utilized throughout the application development cycle. The applications we create will be easy to maintain and enhance. You will be able to leverage the class structure in every application you create. With the right set of tools, building an application becomes a "plug and play" job. At the same time, maintenance becomes a breeze.

In order to gain the most from this session, we are going to look at a very simple example that that may look familiar to you. The example is EX1 that shipped with FoxPro 2.x. This example uses some obsolete features from FoxPro 2.x, such as the foundation read, however, it is a simple example of how most applications work. We are going to build an example very similar to EX1 using class libraries, while looking at each of the objects that make up the application. Then we will explore how easily the application can be modified and enhanced.


EX1: What is it made of?

 

 

 

 

 

 

There are several pieces to the EX1 application. The first is the main program, ex1.prg. This program creates and sets some global memory variables, sets the application environment, calls a the menu, ex1.mpr, and places the application in a "wait state." Once the application wait state is cleared, the application environment is reset.

The menu ex1 is used to drive the application. The menu option, Application, is where all of the forms are located. When one of these forms is selected from the menu, the form appears with a toolbar that is used for navigation. The same toolbar is used for every form, yet when a new form is selected from the menu, a new toolbar does not appear. Once the Quit option is selected from the menu, the application wait state is cleared and the cleanup portion of the main program is executed. This is where the application environment is reset.

Each form has most of the same properties. All of the forms use a window that is centered on the desktop. Each of these windows use Ms Sans Serif, Bold, Size 8 as the default font. The window is a User style window with the following options: Close, Move, Minimize, and Single Border. All of the forms have similar Cleanup Code and Read Deactivate clauses.

Inside each form there are labels, text boxes and edit regions. The text boxes and edit regions are the objects used to enter data into the tables. The labels are the objects that represent prompts for the text boxes and edit regions. This project also contains two utility forms. They are the Browser and Finder forms. These forms are called from the Find and Browse options of the tool bar.


How was it created?

In order to fully understand how creating applications using class libraries will help you create better applications, lets look at what went into creating Ex1 and how one might create an application based on the concepts introduced in Ex1.

First of all, we need to look at what went into creating Ex1. The following items are in no particular order, but they represent all of the components of the application.

In order to add a new screen to the Ex1 application, the following would need to take place:

  1. The new screen would need to be created. The quick screen option could be used to drop all of the labels and text boxes on the form.
  2. The Close option would need to be turned on under the Window options and the border style changed to Single.
  3. The Cleanup Code and READ Deactivate Clause would need to be inserted and changed to reflect the name of the window used for this new screen.
  4. The new screen would need to be added to the project as a screen set along with the tool bar.
  5. The call for the screen would need to be added to the application menu.
  6. The main program would need to be updated to include the new screen program.

A similar set of steps could be followed to create an entire new application based on the concepts in Ex1. When it is laid out in this fashion, it doesn’t look like that much work, however, Ex1 is a simple example that uses many of the FoxPro defaults such as the window style for a form. Each time you want to move away from the defaults, you add a step to the process.

It would be nice if you could create a template, or series of templates, of the type of application you want to create and build each of the applications based on these templates. Then, you would have defaults that match your application programming style rather than FoxPro’s. This is where building applications using class libraries will make application development easier for you.


Getting Started on the Class Libraries

Before we start creating the classes that will be used during application development, we need to decide what items should go into the classes. If we look back at the components of Ex1, we should be able to get a good idea of what items would fit into a class.

In Ex1, the main program saves environmental settings that the application may change, establishes the application operating environment, establishes the application wait state and resets the working environment. This series of events will take place in almost every application we create. Therefore, the main program would fit well as an Application Class object.

The application will be an object that will have custom properties used to store environment information. Also, the application object will become the top of the application hierarchy and common routines will become custom methods of this object. This approach will allow us to keep the common application code in one place where modifications will be amended in every application that uses the object.

Keep in mind that we will still need a main program which will make sure that the application object can be created and will destroy it when the application is terminated.

Just as in Ex1, the application menu will drive the application. Most of the forms, by nature, will be accessed from the menu. The menu differs from other components in an application in that it is more specific to the application. Each application will have different forms and other items that may be called from a menu. Because of this, a menu class may not fit well in the application hierarchy.

The Visual FoxPro Menu Builder does access class objects in the same fashion as the form designer in that class objects cannot simply be dropped into a menu. We will reference methods and properties from our classes through the menu, however it will not be its own class object. A more advanced framework may include an object for managing menus.

In the example, Ex1, the tool bar was created as a separate form. This form was added to the other forms by way of a screen set. Since the tool bar functions are the same for every form it is attached to, it is generic. A Tool Bar Class would fit well into our application hierarchy.

In FoxPro 2.x applications, when the tool bar was included with a form it used the same .SCX file, however the code for it was duplicated in each screen program. Our class structure will be intelligent enough to know when a tool bar is active so that we only have one instance running at any one time. This will help eliminate much of the screen flicker that we see in FoxPro 2.x applications when the user switches windows.

Each data entry form will have many of the same properties. The window style, colors and fonts will always be the same. These properties can be set in a base form class object which would then be used as the template for all data entry forms. Another benefit to using this approach is that any common code can be placed in the form class object as methods and will automatically be inherited by all instances of the form class. This allows us to keep the common code in one place rather than requiring that it be found in each individual form.

In our example, we will not require that a tool bar be used with the form. If we did not want to use the tool bar with a form, we could easily place the navigational command buttons directly on the form.

All of the objects used on a form will have similar characteristics as well. For example, all labels should use the same font and alignment and command buttons should use the same font and colors. If we create a class for each type of object that will be used on a form, we can set the properties at the highest level and all objects based on the parent class will inherit the properties. This will insure uniformity in our forms.


The Code

The Application object will be the driver of our applications, therefore it contains many custom properties and methods. This is similar to the memory variables and procedures that were contained in the main program of your FoxPro 2.6 applications. This class is based on the Custom base class. It is considered a non-visual class because there is not a screen object associated with the class (i.e. nothing you can see <g>). The following table explains each of the properties and methods used in the application class.

Property/Method Value/Purpose Type
Name "Application" P
cDatabase Main DBC Name P,C
cAppname The name of the application P,C
cMainMenu The name of the main menu P,C
nVersion Version Number of the application P,C
cOldScreenCaption The caption of the desktop window before the application runs P,C
cSetTalk Setting of SET TALK P,C
cSetPath Setting of SET PATH P,C
cSaveDir Current directory P,C
cSetClasslib Setting of SET CLASSLIB P,C
cSetEscape Setting of SET ESCAPE P,C
cSetSafety Setting of SET SAFETY P,C
cSetDate Setting of SET DATE P,C
cSetProc Setting of SET PROCEDURE P,C
cSetStatus Setting of SET STATUS P,C
nSetMemo Setting of SET MEMOWIDTH P,C
cSetMultilocks Setting of SET MULTILOCKS P,C
cSetHelp Setting of SET HELP P,C
cSetDeleted Setting of SET DELETED P,C
cSetExclusive Setting of SET EXCLUSIVE P,C
cSetNotify Setting of SET NOTIFY P,C
cSetBell Setting of SET BELL P,C
cSetNear Setting of SET NEAR P,C
cSetExact Setting of SET EXACT P,C
cSetIntensity Setting of SET INTENSITY P,C
cSetConfirm Setting of SET CONFIRM P,C
cOnShutdown Setting of ON SHUTDOWN P,C
lDeveloper Is a developer running the application? P,C
cSetCentury Setting of SET CENTURY P,C
lok2Exit Logical that determines if the Ok2Exit method has been executed yet. P,C
nFormCount The number of forms currently active. P,C
oToolBar The property used to reference the tool bar object. P,C
Destroy In case the application is being exited by a means other than the Quit option on the menu, or clicking the close box, we call the Ok2Exit method to clean up the environment when the application object is destroyed. M
Init Saves the SET environment and set the necessary environment for the application. This also opens the DBC associated with the application. M
Do The DO method which gets the application running. M,C
SaveSets Saves the SET environment M,C
SetSets Sets the SET environment for the application M,C
RestoreSets Restores the SET environment when the application is exited M,C
DoForm Runs a form M,C
DoMenu Runs the menu program M,C
Ok2Exit Determines if it is OK to release the application object M,C
ReleaseToolbar Determines if the Tool Bar needs to be released. M,C
AddToolbar Determines if the ToolBar object needs to be created. M,C

Type: P=Property, M=Method, C=Custom Property or Method

The Tool Bar Class is made up of several pieces. The tool bar is an object itself. The tool bar contains command buttons that allow for navigation and editing. The following table outlines all of the items in the tool bar.

Name Base Class Property/Method Value/Purpose Type
BaseTool ToolBar Caption "Navigation Tools" P
    Height 30 P
    Left 0 P
    Top 0 P
    Width 178 P
    ControlBox .F. P
    Name "BaseTool" P
    Destroy Make the tool bar invisible so that it clears faster. M
    Init Dock the toolbar when it is first instantiated. M
    Refresh Set the enabled property of the Top, Previous, Last and Next buttons based on the status of EOF() and BOF()  
btnTop CommandButton Top 4 P
    Left 6 P
    Height 23 P
    Width 24 P
    Picture ..\bmps\frsrec_s.bmp P
    Caption "" P
    Default .F. P
    Name btnTop P
    Click Run the First method in the Active Form and refresh the tool bar. M
btnPrev CommandButton Top 4 P
    Left 29 P
    Height 23 P
    Width 24 P
    Picture ..\bmps\prvrec_s.bmp P
    Caption "" P
    Default .F. P
    Name btnPrev P
    Click Run the Prev method in the Active Form and refresh the tool bar. M
btnNext CommandButton Top 4 P
    Left 52 P
    Height 23 P
    Width 24 P
    Picture ..\bmps\ nxtrec_s.bmp P
    Caption "" P
    Default .F. P
    Name btnNext P
    Click Run the Next method in the Active Form and refresh the tool bar. M
btnLast CommandButton Top 4 P
    Left 75 P
    Height 23 P
    Width 24 P
    Picture ..\bmps\ lstrec_s.bmp P
    Caption "" P
    Default .F. P
    Name btnLast P
    Click Run the Last method in the Active Form and refresh the tool bar. M
btnNew CommandButton Top 4 P
    Left 104 P
    Height 23 P
    Width 24 P
    Picture ..\bmps\ new.bmp P
    Caption "" P
    Default .F. P
    Name btnNew P
    Click Run the Addthod in the Active Form and refresh the tool bar. M
btnSave CommandButton Top 4 P
    Left 127 P
    Height 23 P
    Width 24 P
    Picture ..\bmps\ save.bmp P
    Caption "" P
    Default .F. P
    Name btnSave P
    Click Run the Save method in the Active Form and refresh the tool bar. M
btnCancel CommandButton Top 4 P
    Left 150 P
    Height 23 P
    Width 24 P
    Picture ..\bmps\ undo.bmp P
    Caption "" P
    Default .F. P
    Name btnCancel P
    Click Run the Undo method in the Active Form and refresh the tool bar. M

Type: P=Property, M=Method, C=Custom Property or Method

The form class has been designed to be very flexible. Since the form determines if the tool bar should be used, the form class controls hiding and showing the tool bar. Also, the methods used to navigate the form are contained in the form rather than the tool bar. This will allow the developer to customize the navigational methods in particular forms. The following table shows the properties and methods used in the form class.

Property/Method Value/Purpose Type
BorderStyle 2 P
BufferMode 1 P
DataSession 2 P
ScaleMode 3 P
BackColor 192,192,192 P
Caption Base Form P
FontSize 9 P
Left 0 P
Name BaseForm P
Top 0 P
lToolBar Should the tool bar be used? P,C
Activate 1. Make sure the alias used for the screen is selected.

2. Make sure that the tool bar is refreshed or hidden when the form is activated.

M
Destroy Sets the visible property to .F. so that the form clears quicker and removes one from the number of forms active. M
Init Checks to see if this form uses the tool bar. If so, AddToolBar in the app class is run to make sure that the toolbar object exists. Also, one is added to the number of forms active. M
QueryUnload Determines if it is Ok to release a form. M
Unload Run the ReleaseToolBar Method in the application object to determine if the tool bar should be released. M
Add Add a new record to the table or view used in the current form M,C
ChangePending Returns a character string indicating if a change has been made to the current record in the current form. M,C
First Display the first record in the data source. M,C
Last Display the last record in the data source. M,C
Ok2Continue Prompts user to save record if necessary before moving the record pointer or closing the form M,C
Next Display the next record in the data source. M,C
Prev Display the previous record in the data source. M,C
Save Save changes to the table or view used in the current form. M,C
Undo Cancels uncommitted changes made to the table or view in the current form. M,C
WriteBuffer Writes the value of a control to the corresponding field if the value has changed. M,C

Type: P=Property, M=Method, C=Custom Property or Method

The purpose of creating a object classes is to set the common properties in the class. Then we will be able to use these class objects on any form and the properties will be the same. In our example, only one of the objects, the text box, contains code in a method.

The Init Method of the custom text box will set the input mask and width properties when the object is instantiated. This will allow us to base these properties on the actual size of the ControlSource used for the object.

The following table illustrates which default properties have been set for each object. This table does not contain all of the possible object types, only the ones that we might use in our example.

 

Object Name Base Class Properties Set
chkCheckBox checkbox Height = 22

Width = 148

FontBold = .F.

FontSize = 9

BackStyle = 0

Caption = "Check1"

Name = "chkCheckBox"

cboComboBox combobox FontBold = .F.

FontSize = 9

Height = 22

Style = 2

TabIndex = 1

Width = 200

DisabledBackColor = 192,192,192

Name = "cboComboBox"

cmdCommandButton commandbutton Height = 22

Width = 80

FontBold = .F.

FontSize = 9

Caption = "Command1"

Name = "cmdCommandButton"

opgOptionGroup optiongroup ButtonCount = 2

BackStyle = 0

BorderStyle = 0

Value = 1

Height = 60

Width = 90

Name = "opgOptionGroup"

optOption1.Caption = "Option1"

optOption1.Height = 18

optOption1.Left = 5

optOption1.Top = 5

optOption1.Width = 68

optOption1.Name = "optOption1"

optOption2.Caption = "Option2"

optOption2.Height = 18

optOption2.Left = 5

optOption2.Top = 25

optOption2.Width = 68

optOption2.Name = "optOption2"

edbEditBox editbox FontBold = .F.

FontSize = 9

Height = 44

Name = "edbEditBox"

lblLabel label FontBold = .F.

FontSize = 9

Alignment = 1

BackStyle = 0

Caption = "Label1"

Comment = ""

Height = 22

Width = 80

Name = "lblLabel"

shpShape shape BackStyle = 0

Height = 22

Width = 80

SpecialEffect = 0

Name = "shpShape"

txtTextBox textbox FontBold = .F.

FontSize = 9

Format = "K"

Height = 22

InputMask = ""

Width = 80

Name = "txtTextbox"

lstListBox listbox FontBold = .F.

FontSize = 9

Height = 66

Width = 80

Name = "lstListBox"

 


Building the Application

Now that we have designed the classes to be used to create our application, we will create it. As you will see, it is very simple to build the application based on these classes. We will be creating a sample application involving three forms, Customer, Offices and Parts. The Customer and Parts forms will use the tool bar and the Offices form will not. Let’s do it!

To start, we need to create a project. Since the menu is not a class, we will copy a template menu to the application directory and add it to the project. We will also add a template startup program to the project and make it the main program file.

The main program will take care of creating the application object, however, we will subclass the application object for each application so that we can set some of the properties that will be specific.

From the Classes Tab of the project manager, select New. The class name will be Sample and it will be based on the Application class in the Startup class library. Then we need to modify this new class and change the following properties:

Now that we have the application class set up, we can create the forms. Before we create a new form, we need to set the Form Template Class to our BaseForm in the Baseform class. This can be done from the Forms tab under the Options dialog. Now we are ready to create a form.

You can follow these same steps for the other two forms as well. Remember that the tool bar will not be used on the Offices form.

The last thing that we need to do is add the appropriate code to the menu that will call our forms. When we open the menu from the Project Manager, you will notice that the Application Menu Pad is empty. This is where the form calls will go. We will be running the forms through the Application object’s DoForm Method. The command with be:

Now we are ready to build the application and run it!


Making Changes

You may be saying to yourself that you could create an application in a similar fashion under FoxPro 2.x, so what is the big deal? Under FoxPro 2.x, you may have had empty forms, text boxes, check boxes...etc, that you used as templates. These worked really well when creating a new application, but what about maintaining applications? If you found a bug in the Setup Code of your template form, you had to make the change in the template form as well as each form, in every application, that used the template.

The beauty of using classes is that properties and methods are automatically inherited! You don’t even need to think about it. When you make a change in the parent class, every object based on that parent will have the change immediately. To gain a better understanding of this, lets look at the following changes...


Conclusion

The one downfall to this approach is that you really have to plan out your applications. There is a great deal of work necessary before you ever start working on the actual pieces of an application. On the other hand, if you don’t do it right the first time, it is very easy to implement the changes. This is very important when it comes to working with a new programming language. When you start working with Visual FoxPro 3.0, you will be lost! You may not do everything the "best" way the first time. It is comforting to know that when you do find the "best" way, you only need to implement the change in one place.