ISTE Home
About ISTE
Advocacy
Educator Resources
Membership
Affiliates
All-Inclusives
Awards and Recognition
ISTE 100
Join or Renew
Member Campaigns
Member Central
Member Networking
My Profile
Podcasts
Special Interest Groups
SIG Newsletter
Join a SIG
SIG1to1 (1 to 1 Computing)
SIGAdmin (Administrators)
SIGCT (Computing Teachers)
Join SIGCT
SIGCT Officers
Journal for Computing Teachers (JCT)
JCSE Online - Journal of Computer Science Education
Past Issues
2005-2006
2004-2005
2003-2004
2002-2003
2001-2002
April 2002
February 2002
November 2001
October 2001
Submission Guidelines
SIGDE (Digital Equity)
SIGHC (Handheld Computing)
SIGILT (Innovative Learning Technologies)
SIGIVC (Interactive Video Conferencing)
SIGMS (Media Specialists)
SETSIG (Special Education Technology)
SIGTC (Technology Coordinators)
SIGTE (Teacher Educators)
SIGTel (Telelearning)
SIG Council
Volunteer
NECC
NETS
Career Center
News & Events
Professional Development
Publications
Research
Store

Printer Friendly

OOPs!

Tim Margush
The University of Akron

Object-oriented programming (OOP) is one of the current buzzwords in computer science. Many programmers are trying to jump on the object-oriented (OO) bandwagon, but not all of them understand what OOP is really about. Bakopanos (2000) presented three different solutions to the problem of applying specific functionality to controls across several forms in a Visual Basic project. The premise of the article was that there was an advantage to using an OO solution to this problem. The author's approach was to show some non-OO solutions and then demonstrate an OO approach to solving the original problem. Unfortunately, the OO solution was not object oriented, only object confused.

As old languages are updated to include the OO paradigm and new OO languages are introduced, changing old programming habits to take advantage of these new capabilities becomes more and more important. There is no substitute for good OO design that springs from an object approach to representing and solving a problem. In this article, I examine the problem presented by Bakopanos (along with his so-called OO solution), explain why that solution is not truly OO, and then examine the OO techniques (inheritance and composition) commonly employed to extend the functionality of an object.

The Problem

Bakopanos’ problem is common in the development of a Visual Basic project in which standard controls are part of the solution. The built-in functionality of the standard controls is seldom sufficient to meet the demands of each project and is intended to be customized to each particular need. In the simplest form, this is accomplished by providing code for various events that are associated with each control. To attain a particular look and feel, it is common for the same customization to be applied to many controls. This solution results in much duplication of code and increases maintenance costs. These specialized routines are often changed during project development, and failure to update all of the controls in exactly the same way leads to errors.

The standard controls used in Visual Basic are intended to be viewed as objects. The design toolbox provides an icon representation of the standard classes (e.g., text box, label, list box, etc.), and the programmer usually instantiates objects of these types by drawing them on a form. This creates an object with the standard functionality described in the associated class definition. Bakopanos sought an OO solution to the problem of ensuring that all (or many) of the controls used in a project have the same display settings and underlying functionality. His ideas were demonstrated in a contrived example by focusing on a single object type, the text box. Each text box in the project was to have two attributes and one behavior that differed from the standard text box (red ForeColor and FontBold turned on, and automatic selection of the text contents when the control's GotFocus event was triggered). Three solutions were proposed, but we will examine only the third, as it is this one that was claimed to be OO. Indeed, the proposed solution used an OO approach to encapsulate the required functionality in a class, but failed to incorporate this functionality as a seamless extension to the standard objects.

An Inappropriate Solution

The solution proposed by Bakopanos includes three parts. The first is a public (global) class definition (Class1) that must be placed in a code module (Figure 1a). The second is the instantiation of an object (mclass1 of type Class1) and the inclusion of some initialization code in the Form_Load event of each form that will contain one or more of the customized text box controls (Figure 1b). The initialization code simply sends each text box control to a method of object mclass1 that sets the text box’s display properties to conform to the customized standards. The third part of the solution is the inclusion of a method call in each textbox's GotFocus event to implement the auto-select feature (Figure 1c).

'OO way

'Class1 code listing

Option Explicit

Public Property Let gTextboxSelectAll(ByVal vTextbox As TextBox)

Dim intWhere As Integer

intWhere = Len(vTextbox.Text)

vTextbox.SelStart = 0

vTextbox.SelLength = intWhere

End Property

Public Property Let gTextboxDisplaySettings(ByVal vTextbox As TextBox)

vTextbox.FontBold = True

vTextbox.ForeColor = vbRed

'Or whatever

End Property

Figure 1a.

Private mclass1 As New Class1

'

Private Sub Form_Load()

mclass1.gTextboxDisplaySettings = Text1

mclass1.gTextboxDisplaySettings = Text2

End Sub

Figure 1b.

Private Sub Text1_GotFocus()

mclass1.gTextboxSelectAll = Text1

End Sub

Private Sub Text2_GotFocus()

mclass1.gTextboxSelectAll = Text2

End Sub

Figure 1c.

The solution is inefficient, misleading, and does not make appropriate use of OO design. It is inefficient in that it requires the instantiation of a separate object for each form. It also requires the programmer to add additional code in the Form_Load and GotFocus events, which if overlooked will result in malfunctioning controls. In addition, the same statements must be written again and again, resulting in a great amount of code duplication.

The solution is misleading, as it uses Properties (gTextboxDisplaySettings and gTextboxSelectAll) of a class to modify the state of an external object (a text box). When an object is sent to a Property procedure, the usual intent is to modify the state of the base object, not the argument. A greater clarity of expression would be attained through the use of a public method of the class rather than a Property.

Finally, the solution is not a result of good OO design. What is really needed is a way to encapsulate the new functionality inside the text box itself, rather than create the customization externally. A good solution would incorporate the custom functionality with no external coding required and would hide the implementation details from the user. None of these objectives are realized in Bakopanos’ solution.

An Object-Oriented Approach

The task to be accomplished was to extend the functionality of an existing object (the text box control). The OO solution would be to create a new class type that incorporates the underlying functionality of the original class and extends its capabilities to implement the desired customization. In OOP terminology, this is often accomplished through a technique called inheritance. By defining a new control (class) that extends the text box class, we would keep all of the original control behaviors, but could customize selected ones with a minimum of programming effort.

Unfortunately, Visual Basic does not support inheritance. Nevertheless, it is still possible to attain the goal without compromising our OO principles. As an alternative to inheritance, programmers sometimes utilize a technique known as class composition. A new class (called a wrapper) is defined. It contains an object of the original type (for example, a text box) as a member. Public methods that duplicate the inner object’s methods are provided so the new class appears to function identically to the original. Custom behavior is incorporated in these wrapper methods, and sometimes, new methods are included. Objects instantiated from this new class type, will then automatically contain all the functionality of the original type, plus the desired custom behavior. No extra code needs to be included in the form modules, and updates to the custom behavior are localized in one place, the new class definition.

This means of accomplishing inheritance is straightforward only when a class is relatively small. The text box control has many properties, methods, and a visual component that must be replicated in the wrapper class. Many methods and properties will need to be extended to the wrapper class. None of the work is complicated, but it is tedious if done manually. Fortunately, Visual Basic provides a powerful tool, the ActiveX Control Interface Wizard, that drastically reduces the overall effort extended.

Inheritance the Visual Basic Way

Here are the steps I took to solve the original problem using an OO approach. Rather than using the ActiveX Control Interface Wizard, I performed each step manually so you can understand the mechanisms involved in extending the original control. The result is a limited version of an enhanced text box control. Feel free to duplicate these steps for yourself.

  1. Begin a new VB ActiveX Control Project. This automatically creates a new user control class (UserControl1) that is the container for our wrapper class.
  2. In the project properties window, set the name of the project to CTextBox.
  3. Rename UserControl1 to CustomTextBox.
  4. Place a standard text box control of default size on the user control design window.
  5. Position it at the top left corner, then resize the user control to match the size of the text box. You can do this by setting the Height and Width properties to match those of the text box.
  6. Name the text box txtText.
  7. Step six accomplishes object composition—including an object as a member of the new class. Now, when a CustomTextBox object is instantiated, it will contain a normal text box as a member. This member is referred to as the constituent control. The CustomTextBox will need to expose properties, methods, and events of the inner text box, to achieve the illusion of inheritance.

    The next step shows how to achieve the behavioral distinction between a standard text box and our new CustomTextBox. When the textbox contained in the CustomTextBox control receives focus, the textbox contents must be automatically selected for editing

  8. Add two statements to the txtText control's GotFocus event (Figure 2).

    Private Sub txtText_GotFocus()

    txtText.SelStart = 0

    txtText.SelLength = Len(txtText.Text)

    End Sub

    Figure 2.

  9. Close the UserControl Object Design window.

The Visual Basic IDE toolbar should now contain a new item, your CustomTextBox control. To test the new control:

  1. Add a Standard EXE project (Choose Add Project from the File menu) to the design environment, creating a project group.
  2. Select the new project as the Start Up project.
  3. Add two CustomTextBoxes to the form of the new project. If you draw this control on the form, you may notice that the inner text box does not resize to fit the size of the user control. You may also notice that the default text contents are the same for each new CustomTextBox; in a standard text box, the default contents match the name of the control. These issues can be addressed with some additional code in the UserControl module. To keep this example simple, we will ignore the need for these "extra features."
  4. Run the program and observe that the text contained in either CustomTextBox is automatically selected when the control gets the focus. You can change the focus between the two controls by pressing Tab or clicking with the mouse.

This automatic text selection functionality will now occur for every CustomTextBox object on any form of any project. You do not need to write any additional code to make it happen. Already we can see a great improvement over the solution proposed by Bakopanos. There is no need to instantiate a class in each form to provide the custom routines for automatic text selection. There is no need to add a method call to each text box’s GotFocus event to implement the new functionality and there is no possibility of forgetting to add this statement, which would result in a text box that lacks the desired custom behavior. Indeed, the customization is now automatic, and totally transparent to the application programmer.

Exposing Properties

Much work still needs to be done to make the CustomTextBox control useful, however. As it stands, there is no way for the application to access the important properties of the inner text box. If Visual Basic provided inheritance, this visibility would be automatically provided; one would simply add the additional code necessary to implement the desired customization. In Visual Basic you must implement the connection to the original control manually.

In most OO languages, we would solve the problem of providing access to the nested object either by making the object public (which goes against the standard conventions dealing with information hiding) or provide get and set methods in the wrapper class that allow access to the nested object’s properties. Both of these approaches result in syntax requirements that work against the transparency of the solution, especially in Visual Basic, where properties of a control appear to function as public data members, even when they are not. In Visual Basic, special methods, known as property procedures, are used to create properties of a control that imitate (both in syntax and functionality) the properties of the standard controls. This allows the solution to retain the same syntax as would be used with a standard text box while retaining the protection afforded by the traditional get/set paradigm.

Nearly all uses of a text box control require access to its Text property so we will focus on this to illustrate the process of exposing a property. The goal is to create a new property for the CustomTextBox control that imitates the constituent control's Text property. Figure 3 shows how to make the inner text box’s Text property visible outside the User Control by adding two Property procedures to the user control’s code window.

Public Property Get Text() As Variant

Text = txtText.Text

End Property

Public Property Let Text(ByVal New_Text As Variant)

txtText.Text = New_Text

PropertyChanged "Text"

End Property

Figure 3.

The new code adds a Text property to the CustomTextBox control that exactly imitates the inner text box’s corresponding Text property. Even the syntax is identical. Figure 4 shows the code necessary to implement a simple test of the new property. The test will display the text stored in a CustomTextBox control in a message box and then clear the CustomTextBox when the message box is closed. To carry out this test, you will need to add a command button to the test project form, and place the code in Figure 4 in its Click event.

MsgBox CustomTextBox1.Text 'Uses Get method

CustomTextBox1.Text = "" 'Uses Let (set) method

Figure 4.

Run the project, enter something in CustomTextBox1 and click the command button. The contents will be displayed in the message box. When the message box is closed, the text in CustomTextBox1 will be cleared.

Selecting Default Property Values

Our CustomTextBox is still lacking many features of the usual text box control. To make this control really useful, we will need to do quite a bit more work. Our new control only provides access to the constituent text box's Text property. By imitating the technique used to expose this Text property, we can expose any other properties that we think will be useful. We can also establish new persistent defaults for the inner text box’s properties that can be selectively changed for each object. This will provide an elegant solution to the next part of the problem, to establish a consistent look for all of the CustomTextBox controls in a project without sacrificing flexibility. Once again, we will illustrate the technique manually; for real applications, the ActiveX Control Interface Wizard is a powerful tool to help the programmer map the inner control’s properties, methods, and events to those of the container.

To satisfy Bakopanos’ original requirements of bold style and red text, we could simply set the constituent control's (txtText) corresponding properties, but this would not allow the programmer to override these new settings for CustomTextBox objects when they are placed on a form. A better solution is to expose the FontBold and ForeColor properties of the text box, and establish new default values. Figure 5 shows the code required to accomplish these changes.

'Default Property Values: (these go in the General Declarations area)

Const m_def_ForeColor = vbRed

Const m_def_FontBold = True

'Initialize Properties for User Control

Private Sub UserControl_InitProperties()

txtText.ForeColor = m_def_ForeColor

txtText.FontBold = m_def_FontBold

End Sub

'Read property values from storage

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)

txtText.FontBold = PropBag.ReadProperty("FontBold", m_def_FontBold)

txtText.ForeColor = PropBag.ReadProperty("ForeColor", m_def_ForeColor)

End Sub

'Write property values to storage

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)

Call PropBag.WriteProperty("FontBold", txtText.FontBold, m_def_FontBold)

Call PropBag.WriteProperty("ForeColor", txtText.ForeColor, _

m_def_ForeColor)

End Sub

'Expose ForeColor and BackColor properties

Public Property Let Text(ByVal New_Text As Variant)

txtText.Text = New_Text

PropertyChanged "Text"

End Property

Public Property Get FontBold() As Boolean

FontBold = txtText.FontBold

End Property

Public Property Let FontBold(ByVal New_FontBold As Boolean)

txtText.FontBold = New_FontBold

PropertyChanged "FontBold"

End Property

Public Property Get ForeColor() As OLE_COLOR

ForeColor = txtText.ForeColor

End Property

Public Property Let ForeColor(ByVal New_ForeColor As OLE_COLOR)

txtText.ForeColor() = New_ForeColor

PropertyChanged "ForeColor"

End Property

Figure 5.

To see this in action, you must be sure the user control design window is closed, then remove the original CustomTextBox controls from the test form and add two new ones. Each should be instantiated with red text in the bold style. Select one of them, and change the FontBold property to false. This setting will be retained in that control's Property Bag. The Property Bag can be used to make any of the properties set at design time persist across multiple invocations of the control. The ActiveX Control Interface Wizard can automatically handle the creation of this Property Bag code.

By exposing these two properties, and employing the Property Bag technique, we have created custom default properties for our control. Each new instance of the CustomTextBox control automatically begins with these default settings. The programmer is free to change them for particular instances at design time, or runtime. Furthermore, by multiselecting all of the CustomTextBox controls on a from (you do this by holding down the Ctrl key as each is selected), the font properties can be set for all at the same time, achieving the desired consistency without sacrificing flexibility. This results in another tremendous improvement over Bakopanos’ non-OO approach. By establishing custom defaults, each instantiation begins with the desired attributes. By introducing persistent property settings, we allow the programmer to override the defaults in a consistent and straightforward way. Because there is no need to place initialization code in the Form_Load events, there is no possibility of forgetting to invoke this code. In addition, unlike the non-OO solution, the programmer is free to override those defaults for individual objects. In short, the CustomTextBox behaves just like a standard text box, with new default values.

Exposing Events

Although the CustomTextBox control as it now stands meets the requirements imposed by Bakopanos, our solution has inadvertently handicapped the programmer. Since Bakopanos simply programmed the custom behavior into each text box, all of the original text box’s functionality would still be available, but the CustomTextBox, so far, has exposed only a few properties, and the text box’s methods are still hidden inside the wrapper. Additional properties (indeed, all of them) could be exposed as required, but to complete the illusion of inheritance, the events associated with the text box need to be connected to events associated with the CustomTextBox. The Change event, for example, is sometimes used to validate the information entered in a text box. Although the text box txtText can respond to change events, the event is not passed out to the CustomTextBox control level. As a result, the application programmer cannot write any code to program this event. However, by adding just a few lines to the CustomTextBox control’s code, we can provide this functionality (Figure 6).

Event Change() 'This must go into the General Declarations area

Private Sub txtText_Change()

RaiseEvent Change

End Sub

'For testing, add this code to the test project

'It customizes the Change Event for CustomTextBox2

' causing each change to be duplicated in CustomTextBox1

Private Sub CustomTextBox2_Change()

CustomTextBox1.Text = CustomTextBox2.Text

End Sub

Figure 6.

Run the program and notice that each change to the CustomTextBox2 causes the contents to be duplicated in CustomTextBox1.

Conclusions

Implementing a custom look and feel in a control across all forms in a project, while retaining the simplicity of drag and drop design, is efficiently accomplished in Visual Basic using an OO approach. Although Visual Basic does not support object inheritance, it does allow class composition. By using this simple OO technique and the ActiveX Control Interface Wizard, it is a fairly simple task to create a custom control that inherits the essential functionality of an existing control, but adds additional properties and methods that are desired for specific applications. The use of Property methods allows these custom controls to mimic the standard controls in every way.

Bakopanos presented a basic solution to the problem of modifying a standard control to achieve custom functionality and appearance, but his solution fell short of its potential. It required special code to be written at the application level rather than hiding it within the control code itself. Requiring this additional code violated the basic OO principle of information hiding and resulted in a solution that was inflexible and prone to error. In addition, by separating the custom code from the object to which it was to be applied, he also violated principles of encapsulation. The solution developed in this article, applied class composition to provide a truly OO approach that illustrated the principles of information hiding and encapsulation. We also saw how the ActiveX Control Interface Wizard could be used to imitate inheritance, even though it is not a feature of the Visual Basic language.

As a final note, regarding object reuse, the Visual Basic IDE provides a method of packaging this new control to make it instantly available to any project. By compiling the CustomTextBox control to create an ActiveX Control file (CustomTextBox.ocx), it can be included in the project components of any new project. By simply dropping an instance of this control on a form, we get all of the desired custom functionality, plus the added benefit of modifying any of its properties or methods on an individual control basis.

Reference

Bakopanos, K. (2000, February). Applying functionality on controls the OO way. Visual Basic Online [Online serial]. (Note: At press time, this periodical was no longer available online. It may reappear, however. If it does, we will add the link so that you may read the piece that inspired this article.)


Contributor

Dr. Margush has been teaching computer science for over twenty years. His main interests are in the area of discrete mathematics and software development in Visual Basic, C++, and Java. He has authored several custom packages for various non-profit organizations and engaged in consulting activities with several firms.

Tim is active in community organizations, and has appeared in several drama productions through his church. When he is not thinking about programming, he enjoys spending time with his family or singing and playing guitar.

Contact

Dr. Tim Margush
Department of Computer Science
The University of Akron
Akron, OH 44325
Margush@uakron.edu
www.cs.uakron.edu/~margush
330.972.7109

Copyright © 2001, ISTE (International Society for Technology in Education). All rights reserved.

Customer Service: iste@iste.org   1.800.336.5191   1.541.302.3777 (Int'l)   1.541.302.3778 (fax)
Visit the ISTE Career Center for educational technology jobs, resources, and listings.