Visual Class Designer


This document is reprinted from the Microsoft DevCon 95 Speaker materials and is provided "as-is." This document and any associated demo files were created using Visual FoxPro 3.0. Some features discussed may have changed in Visual FoxPro 5.0.

Ken Levy

Flash Creative Management, Inc

Introduction

Along with the new object-oriented programming (OOP) language extensions, Visual FoxPro 3.0 also includes a Visual Class Designer development tool for creating and managing class libraries. This session includes a detailed explanation and demonstration of the Class Designer and how it interacts with other related Visual FoxPro tools. Rather than re-writing the Class Designer chapter of the Visual FoxPro manual, these session notes are designed to give architectural information about the Class Designer and how it relates to other Visual FoxPro tools such as the Form Designer and the Class Browser. Refer to the Visual FoxPro 3.0 manuals on the Class Designer for a detailed descriptions and illustrations as a supplement to these notes.

Objects vs. Functions

Many developers new to object-orientation often question the difference between objects and user-defined functions (UDFs). First, let’s discuss the concept of abstraction.

Abstraction involves concepts such as information hiding and black-box segments. The idea is to create reusable software components in which users of these components do not have to have knowledge of their internals in order to use them. In structured design, abstraction is implemented with functions. In object-oriented design, abstraction is implemented with objects.

The primary difference between functions and objects is that functions (UDFs) are basically behaviors or logical code routines. Objects, on the other hand, are a collection of functions known as methods and data known as properties or attributes. Objects are self contained entities at runtime based on a blue-print design known as a class. Objects take information hiding one step farther by introducing the next step beyond abstraction, which is known as encapsulation. Encapsulation involves embedding methods (functions) and properties (variables) together while hiding any details of the objects’ internals. Each object is given its own responsibilities.

Another way to think of an object is the concept of abstract data types, which is simply a high level structure that relates to real world objects better than standard language data types.

Object-orientation introduces another significant concept known as inheritance. A useful analogy for inheritance involves defining genetic cells, or DNA. Think of how organisms reproduce and contain both behaviors and attributes from the organisms of which they were derived. Usually there are many similarities, but always some differences. You could think of the original DNA structure like an original blueprint. Then think of the offspring as a modified blueprint based on the original. Realize that an entirely new blueprint was not created from scratch, but rather referenced from the original with certain changes or differences.

In object-oriented terms, software DNA are known as classes. Classes are simply definitions at design time from which objects are created, or instantiated, at runtime. Classes define both behavior (methods) and attributes (data) which are basically templates that generally map real world concepts down to a software level. New class blueprints can be created from scratch (these are known as base classes), or can be derived from existing classes (known as subclassing). When subclasses are created, the original class is then referred to as the superclass of the subclass, and the entire process is known as inheritance.

Based on these concepts, class hierarchies can be constructed for related classes, allowing maximum reusability. Groups of related class hierarchies can be bundled together to create class libraries. Once class hierarchies are created at design time, then objects can be instantiated at runtime.

Once objects are active in memory, program execution basically consists of objects sending messages to other objects. A Draw message might be sent to a box object to draw itself, a Print message might be sent to an invoice object to print itself, and a Print message might be sent to a document object to print itself. Creating common method names such as Print, Draw, Refresh, etc. that are independent of the object type is known as polymorphism.

Polymorphism allows a common sequence of messages to be sent between objects. If classes defining the objects are modified or redefined, the sequence and content of messages don’t necessarily change. The details of a box, invoice, or document could all be modified or completely redefined at the class level while the actual program execution would remain unchanged. In a pure object-oriented system, the only procedural code consists of objects being created, objects sending and receiving messages, and objects being destroyed. So the question you might be asking is, “how do these new concepts and new terminology relate to my current coding practices?”

If you write well thought out modular procedural code that is focused on reusability, then you’ve got a significant head start on OOP. Many FoxPro developers have traditionally jumped right into coding when starting an application. Without having the problem completely defined and thought out, individual pieces of the application are written and then eventually glued together towards the end of the development cycle. Also, the pieces usually rely on each other in order to function properly. There might be situations when you have to make a change to a piece of an application which results in having to change other areas of the source code since they are dependent on each other. One example would be having to change the standard background color for all forms in the application since each form would have to be modified. A more significant example would be having to add a new attribute to all employee related data, like the addition of an employee e-mail address. This would not only affect the data tables, but also any logical code which interacts with the data. GUI forms and reports that display or edit the employee information would all need to be modified individually. Some of the many benefits of object-oriented programming are that application modifications like these become easier, require less effort, and are less likely to result in negative effects on other components in the system.

Visual Classes vs. Coded Classes

VCXs vs. PRGs

Choosing between implementing classes using the Class Designer (VCXs) or through standard code files (PRGs), it is simply a design decision. Using the Class Designer to implement classes offers many more benefits than creating classes in PRG files. With the Class Designer, you can create subclasses using the Class Designer or create instances on forms using the Form Designer. Along with being able to use visual tools for increased productivity, visual class libraries (VCXs) hierarchies can be viewed in various ways using the Class Browser.

Class Hierarchies

When you design a class hierarchy, you are defining a structure which by definition should remain intact. If you make a change to a particular class, the change should be reflected in any of its subclass or any composite class using that class as one of its properties. If a change you are about to make to a class may have a negative effect on existing related classes, that is probably a sign that you need to create a new subclass rather than change the existing one. Classes should relate in an abstract way, meaning you should not have to know how they work internally in order to use or interface to them.

Class Implementation

In a typical business application, you have screen objects like an entry for the phone number or an OK or Cancel button. Most applications contain more than one form with one of these same objects. Beyond that, many apps use the exact same controls as other apps. So essentially you’re duplicating work over and over. Now suppose you want to make a change to the standard, like the phone number format mask or validation, or even the color of a button or entry textbox.

If you make a change to your single class definition, changes will propagate throughout every form, application, etc. which use that class. You could change the standard color of a particular control and you wouldn’t even have to open any of the existing forms in order to inherit the change. Just run the form or program and the new properties and methods take effect.

ADD OBJECT vs. CREATEOBJECT()

There is a very important difference between ADD OBJECT at the class template and CREATEOBJECT() for a member declared as a property at the class template level. The rule is that when you use ADD OBJECT in a class definition, the object becomes a member of the container and can use the Parent property to refer to the immediate container object.

When using CREATEOBJECT on an instance variable of an object, that property is simply being used as a reference to the instance of the newly created object, but is not a member of the container and therefore cannot use the ‘parent’ property since the object is not part of the container.

Class Designer vs. Form Designer

Classes vs. Code Generation

With Visual FoxPro 3.0, when you find yourself saying “I could do it in 2.6 by modifying GENSCRN or using GENSCRNX”, this should be an indication for you to start thinking about a class hierarchy to solve the problem using object-orientation. There is no reason for code generation with Visual FoxPro since it is now an object-oriented language. You can build classes and class relationships which allow you the same flexibility as FoxPro 2.x code generation (SPR) but with the power of encapsulation, polymorphism, and inheritance.

Returning a Value from a Modal Form

The following is an example wrapper class used to allow forms to return values. It uses a simple naming convention that the return value memvar must be called luRetValue. Since dialog forms which return values are normally modal, the example assumes that the form called is modal.

*-- The DoForm class is the wrapper class and 
*--  the DoForm UDF is used to call it.
*-- Simply set memvar luRetValue in any code 
*--  snippet within a form/control method.
*-- The exit code for the form should be 
*--  RELEASE thisform *and* CLEAR EVENTS.
*-- This example set would need to be enhanced 
*--  to support parameter passing to the form.

? DoForm("MyForm.SCX")	&& Form MyForm.SCX should set
										&& luRetValue for the 
										&& return value.
RETURN

FUNCTION DoForm(tcFileName)
LOCAL oDoForm
oDoForm=CREATEOBJECT('DoForm',tcFileName)
RETURN oDoForm.Show()

DEFINE CLASS DoForm AS Custom

	cFileName=''

	FUNCTION Init(tcFileName)
	this.cFileName=tcFileName
	RETURN .T.
	ENDFUNC

	FUNCTION Show
	PRIVATE luRetValue
	luRetValue=.T.
	DO FORM (this.cFileName)
	READ EVENTS
	RETURN luRetValue
	ENDFUNC

ENDDEFINE

VCX vs. SCX

Components of an application are developed in the Class Designer (VCX) by creating classes visually while applications are assembled in the Form Designer (SCX). Not every line of method code and every property setting needs to be saved as a class when building an application. So adding code and setting properties to objects in an SCX makes sense if specialized changes are not intended to be reused. The SaveAsClass function makes it easy to create classes in a VCX from objects in an SCX.

The Class Designer allows developers to create classes visually. These classes can be either visual or non-visual (Custom) subclasses. Custom properties and methods can be added to a class which appear in the Properties window for visual editing. The Form Designer allows forms to be created by subclassing existing classes by dropping them onto the form surface from the Controls toolbar or from the Project Manager.

The object model in Visual FoxPro supports container classes. Container classes are classes which can contain objects as members. The Form and Formset in an SCX is a container. The Formset can contain Form objects while the Form can contain control and Custom objects. The Toolbar class is a container which can contain control objects. Control classes such as the CommandButton class is not a container class since it cannot contain objects.

If you experiment with the Save As Class... menu option when in the Form Designer, you’ll notice you can save controls as classes into a VCX (visual class library). You can also select multiple controls and save all selected controls. You can even save an entire form (including it’s object members) as a single class. When you select an individual control (or just the form) and you save the selected (single) object as a class, you are creating a class based on the object’s classification. When you save a group of selected controls or the entire form which contains controls into a single class, you are actually saving a container class.

Adding Properties and Methods to Classes

Visual FoxPro’s object model does not allow you to add properties or methods to objects within a container class. Now how does this relate to the form designer and the fact that methods and properties can be added to the form, but not any of the controls? The answer is in the above description when you realize that when you create a form (SCX) using the form designer, you’re actually creating a single Form (or Formset) container class.

Since Visual FoxPro does not allow object members of a container class to add methods and properties visually, the Add Property... and Add Method... dialogs in the Form Designer and Class Designer only apply to the form (or Formset) and not any of the added object member controls and custom objects. The Form Designer is actually creates a single container class (either Form or Formset), just like a container class built using the Class Designer, the same rules apply. Only the highest level parent can have added custom properties and methods. When in the Form Designer, you are not defining classes, you are actually manipulating live object instances in a design mode.

Containers vs. Non-containers

For ease of use, Visual FoxPro allows you to define child object properties (using the WITH clause of ADD OBJECT) and object code (ex. FUNCTION Command1.Click) within a container class. However, you shouldn’t do it if you plan to reuse the added object. The following example demonstrates the reusability problem:

DEFINE CLASS MyForm AS Form

	Caption="My Form"
	ADD OBJECT cmdButton AS CommandButton WITH ;
		Caption="Not reusable"

	FUNCTION cmdButton.Click
	WAIT WINDOW ;
		"Not reusable in other classes or subclasses"
	RETURN
	ENDFUNC

ENDDEFINE

Now if you want to build another form, you can’t reuse the implicit CommandButton subclass embedded within my MyForm class. If you were to generate code from a Visual FoxPro SCX which was built using the Form Designer, the code would also look like this. Essentially, the Form Designer is a tool to implement a single form or formset container class. The key is to avoid this technique if you plan to reuse the child objects. For example, you can’t reuse a CommandButton which sits on a form (SCX) in the Form Designer. You must first save it as a class or define it as an independent class. The proper object-oriented way to do the above example is as follows:

DEFINE CLASS MyForm AS Form

	Caption="My Form"
	ADD OBJECT cmdButton AS MyCommandButton

ENDDEFINE

DEFINE CLASS MyCommandButton AS CommandButton

	Caption="Reusable"

	FUNCTION Click
	WAIT WINDOW ;
		"Reusable in other classes or subclasses"
	RETURN
	ENDFUNC

ENDDEFINE
Now you can use the MyCommandButton class in other classes or subclass it.

Custom Builders for Visual Class Libraries

Builders in Visual FoxPro are programs which interact with a form or any of its controls while in the Form Designer or Class Designer. Builders allow direct manipulation of properties and methods while in design mode. The general difference between Wizards and Builders is that Wizards are designed to quickly step you from point A to point B for a particular process while Builders are used to edit methods and properties of live objects in the Form/Class design mode.

Builders are re-entrant, which means they interact with existing properties and methods of an object or objects and often act like a user-friendly object editor. Visual FoxPro 3.0 ships with many built-in builders for classes on the Standard control toolbar (Textbox, Editbox, Grid, Combobox, Listbox, etc.) along with special Builders such as the Form Builder and the AutoFormat Builder. The built-in Visual FoxPro Builders are packed in an application called BUILDER.APP.

When using _BUILDER=“<path>BUILDER.APP”, BUILDER.APP will check the selected object for a custom property called Builder. If a custom property called Builder of type ‘character’ exists and contains a valid .PRG, .FXP, .APP, or .SCX file name, then the builder specified by the Builder property will be executed. The purpose of the reserved Builder property is for declaring a specific builder within a class definition using the Visual Class Designer (VCX). This will allow custom Builders to be distributed along with class libraries. Simply keep the associated Builders in the same directory as the class libraries (VCXs) to allow a specific Builder to be executed. Creating a custom Builder property can be useful with custom class libraries (VCXs) when subclassing in the Class Designer or adding object instances in the Form Designer since the Builder can act as a high-level interface between the developer and any method and/or property members of the class.

Class Browser

The Class Browser in Visual FoxPro 3.0 is written in FoxPro and is specified by a system variable named _BROWSER which defaults to _BROWSER=SYS(2004)+”BROWSER.APP”. The Class Browser opens a single or multiple visual class libraries (VCXs) and is a modeless application. The Class Browser is launched by selecting Browser from the FoxPro system menu which executes the program defined in a system variable called _BROWSER. The Class Browser supports both visual and non-visual (Custom) classes. Multiple instances of the Class Browser may be launched. Selecting Browser from the FoxPro system menu always launches a new instance while the Window menu list is used to activate an existing instance.


GlossaryJ

Abstract Data Type

A data type defined by the programmer which is not supported by the language. These data types are generally high level definitions within a program that correspond to real world objects.

Abstraction

The benefit of ignoring irrelevant details of software components and focusing on only those details required to interface, send messages, etc. Some of the concepts of abstraction include information hiding and black box routines. Since most real world objects include abstract details, objects allow an improved representation of real world objects as compared to functions.

Class

A blueprint, or template, for defining methods and properties of a particular type of object. Classes are defined at design time and are not executed at runtime. Objects are created based on class blue-prints at runtime. Multiple objects can be created (instantiated) from a single class at runtime.

Class Hierarchy

A tree structure of classes which represent the relationship between a set of classes of similar type. The top node of a class hierarchy is known as the base class while related classes below it are known as subclasses. Although any number of levels of subclasses can be created, most methodologies state that well-defined class hierarchies should not exceed about five levels deep.

Composite (Container) Object

An object that contains one or more objects. This occurs when at least one instance variable of an object is of type object. Composite objects, along with delegation, are typical techniques to eliminate the unwanted side effects of multiple inheritance (see inheritance below).

Delegation

Delegation occurs when an object receives a message and passes it on to another object. Delegation is useful when responsibilities of objects are passed on to other objects. Non-OOP languages can also support delegation simply by defining a UDF to simply pass any parameter(s) on to another UDF. The interface to the developer sending the message does not have to know about the internal details.

Encapsulation

The concept of methods (procedures or functions) and properties (data memory variables) packaged together. The result of this packaging is the object. Objects contain both methods and properties. The methods are referred to as the object’s behaviors and the properties are referred to as the object’s attributes.

Inheritance

When a class is derived based on another existing class, the existing methods and properties are referenced for reuse with the new class. A subclass uses all of the methods and properties defined in the superclasses above it within the class hierarchy. Inheritance can be broken for individual methods and properties when creating a subclass. This is known as specialization.

Generally the term “inheritance” implies single inheritance. In some languages such as C++, multiple inheritance is supported. In multiple inheritance, a single subclass can be derived from more than one superclass. Along with the problems of naming conflicts within the union of methods and properties of the superclasses, multiple inheritances is usually considered an improper class hierarchy design solution. The combination of composite objects and delegation is superior to multiple inheritance.

Instance

A term which describes a runtime occurrence of an object belonging to a particular class. Classes are defined at design time, while object instances are created from defined classes at runtime.

Message

An instruction from one object (the sender) to another object (the receiver) to execute one of the receiver’s methods. The three parts of a message are defined by the receiver object name, the method name, and any parameters the method may require. Messages can also be two-way, which occurs when the receiver object’s method returns a value to the sender.

Object

A software collection of related methods (functions) and data (memory variables). Generally the methods act on the associated data. Generally an object refers to an instance of a class.

Polymorphism

The ability to send the same message to various objects while each object is responsible for acting on the common message. Polymorphism allows a common interface to be created for objects sending messages. For example, sending the message “Draw” to both a box object and a circle object would be an example of polymorphism since the message that was sent to each object had the same name while each object contained its own Draw method. A Draw method would be defined in both the Box class and the Circle class and each may have similar or completely different behaviors. Polymorphism is supported by allowing the same method name to be defined within different classes.