Kristi Lombard

Application Development with
MapObjects and Visual Basic

MapObjects will likely be the programming environment of choice for programmers wishing to build mapping capabilities into an application developed within a Windows based programming environment. While many GIS application developers may be familiar with ArcInfo and ArcView as an application development environment, they may be less familiar with MapObjects and the programming environments that MapObjects is designed to work within. The purpose of this paper is to provide an overview of Object Oriented Programming and to provide techniques for taking advantage of the constructs that such an environment provides. This paper then discusses specific techniques for building an application with MapObjects within a Visual Basic environment.

Introduction

The last several years have witnessed a significant shift toward personal computers with a Windows based environment. Complementing this shift is the advent of numerous programming environments that are designed to leverage the advantages associated with Windows. Visual Basic, Visual C++ and Delphi are examples of programming environments that enable users to quickly and efficiently create programs that are robust and easy to use.

GIS programmers working in a Windows environment have several choices of programming environments. Using the NT operating system, choices include ArcInfo, ArcView or MapObjects. The Windows 95 operating system offers GIS programmers ArcView and MapObjects. Most GIS developers are familiar with ArcInfo and ArcView, but perhaps less familiar with MapObjects. MapObjects is a set of mapping and GIS components for application developers. MapObjects consists of an OLE Control and a collection of programmable OLE Automation objects. MapObjects can operate within any programming environment that supports OLE controls. MapObjects is an ideal for those wishing to work within a "visual" programming environment such as Visual C++ or Visual Basic.

There are several reasons a programmer may choose to develop an application with MapObjects rather than ArcView. In some situations, MapObjects offers many benefits to developers. It provides great flexibility that allows developers to create customized applications. The smaller memory footprint, or RAM requirements, allows for streamlined applications that are quick and efficient. And, the "visual" nature enables developers to implement a RAD (Rapid Application Development) paradigm.

This paper focuses on application development using MapObjects in a Visual Basic environment. First, an overview of Object Oriented Programming is provided and relevant key terms and concepts of are defined. The latter section addresses coding standards and code optimization methods for building an application with MapObjects with Visual Basic.

Overview of Object Oriented Programming

The theory of Object Oriented Programming (OOP) was originally formulated in the process of creating languages intended to simulate real life. The first OOP language was Simula 67, developed in the sixties to solve simulation problems. Simulation modeling, such as queuing theory and discrete event simulation, is too complex to model in a procedural way. A classic example is the bank teller problem, which involves sets of tellers, customers, transactions, and various events and time distributions. OOP was designed to capture the event driven nature of simulation with the ability to capture all potential interactions in a short period of time.

The object oriented model is a set of design principles that can be implemented in any programming language. There is no standard definition of OOP; the tools available to the programmer depend on the programming environment. The more powerful OOP programming languages have more built in constructs. Some languages are true OOP, such as Ada and SmallTalk. Most languages are not true OOP but hybrid OOP languages. That is, they implement some OOP concepts, yet they also allow procedural construction in programs. Hybrid languages vary in the degree to which they can be considered OOP. They range from powerful languages (e.g., contain most constructs that enable OOP), such as C++ and Delphi, to less powerful (e.g. contain fewer OOP constructs), such as Visual Basic.

There are many benefits of using an OOP approach. The basic principles of the OOP paradigm are listed below:

  1. Reusable and maintainable. The object is designed so that it is flexible to solve many problems of the same type, rather than just the specific problem at hand.
  2. Extensible. The object can evolve with new requirements. This is helpful in simulating change and growth.
  3. Robust. The object is free of errors and safe from errors in other objects.
  4. Compatible. The object is independent yet can interact with other objects when required. Each object makes as few assumptions about other objects as possible, containing just the necessary information to relate and interact with other objects.
  5. Efficient. The object performs its task quickly, using as few resources as possible. Code reuse encourages efficiency.
  6. Ease of use. The object is intuitive because it is based on real world examples.
  7. High integrity. The object does not contradict itself nor the environment by identifying external object interactions

The Basic Building Blocks of OOP

Objects and classes are the basic building blocks of OOP. Often the two concepts are (incorrectly) used interchangeably, however they are fundamentally different.

Object

An object is a "black box" that receives and sends messages. The object contains code (sequences of computer instructions) and data (information that the instructions operate on). Traditionally code and data have been kept apart. For example, in the C programming language, units of code are called functions, while units of data are called structures. With OOP, the code and data are merged into an object. The user of an object should never need to peek in side the "black box."

Ideally in creating an object, it should be as functional, reusable and persistent as the everyday object that is being modeled. For example, a "telephone object" in the computer should look and act like a real-world telephone, and it should be as intuitive and easy to use. The object would have to change only when the real-world phone changes. Since the object closely represents the real-world phone, it is easy to determine what changes should be made and where these changes should be made.

The ability to modify software is very important. As the popular adage states, "Software is not written, it is rewritten." It is also a well-documented fact that 70% of the cost of a software system is maintenance, and a large part of maintenance is making sure that the software system is in line with changes occurring in the real world.

Objects have properties, behaviors and relationships. Properties are the features of objects that indicate the current state of being. For example, the Color property of the telephone object is green. Behaviors are the features of objects that enable them to respond to stimuli. For example, when a phone call comes in, the phone will ring. Relationships are the features of objects that indicate their association with other objects. For example, a user is related to their telephone by ownership.

Class

Objects are defined by its class, which determines everything about an object. Classes enable objects to be grouped based on common properties, behaviors and relationships. An object is an individual instance of a class. For example, two coworkers may each have a telephone; that is, there are two distinct telephone objects belonging to the same class telephone. The two telephone objects thus have properties from being an instance of the class telephone. For example, they both have a handset for the user to speak into, and a keypad for dialing. The two telephone objects also have the behavior of ringing upon an incoming call.

It is important to remember that the class is only a concept and only objects can have values associated with properties. For example, the value of the Color property cannot be assigned to the class telephone, because each phone could have a different color. But the value of the color property can be assigned to an instance of the class telephone.

More OOP concepts

Following is a partial list of concepts that are important to object oriented programming; encapsulation, inheritance, polymorphism and persistence.

Encapsulation

Encapsulation is the bundling of details of objects so that they are self contained and identifiable. In the real world, objects are easily identified. For example, a person's hand is part of that person, but a glove is not. The goal is to build encapsulated objects with strong internal integrity and direct flexible access between objects (loose coupling). This coupling between objects leads to hiding implementation details, which leads to modular, reusable and maintainable code. Objects interact with each other by calling each other's methods, setting each other's properties and sending each other messages.

As mentioned above, objects are encapsulated at the class level. The class definition, then, will contain most of the information about an object. The key to encapsulation is defining the interface that forms the boundary between the object and the environment. There are four related concepts:

  1. Identity. The object should be uniquely identified from other objects, especially those in the same class.
  2. Modularity. To reduce redundancy, handle the object in only one place and in only one way.
  3. Information hiding. Keep information contained within the object (private) unless it is required by another object.
  4. Coupling. Keep objects as loosely coupled as possible, so that objects do are not dependent on other objects in order to function.

Inheritance

Inheritance is the ability to create a new class based on an existing class. The new class' events, properties and methods are derived from the original class. In this manner, classes can be constructed hierarchically. Returning to the telephone example, the telephone class has the property of having a handset. The telephone class can have subclasses for phones of type cordless and mobile. The cordless and mobile phone subclasses inherit the properties of having a handset. Inheritance avoids redundancy in definition, which can lead to errors.

A classic example is the shape class where the base type is "shape." Each shape has a size, color, and position property. From the base shape class, specific types of shapes, such as circle and rectangle, can be derived (inherited). Each derived shape will have the size, color and position properties. In addition the specific shapes may have additional characteristics. For example, the rectangle shape can have a height and width property, whereas the circle shape may have a diameter property. The type hierarchy embodies both the similarities and differences between shapes.

Polymorphism

Polymorphism literally means "Many Shapes." Polymorphism is related to inheritance and allows objects to maintain the same interface and behavior across multiple classes, even when the underlying implementation is different.

When dealing with type hierarchies, the programmer may often want to treat an object not as the specific type that it is but as a member of its base type. This allows the programmer to write code that does not depend on the specific types. In the shape example, functions manipulate the generic shape without reference to whether it is a circle or rectangle. All shapes can be drawn and erased; these functions simply send a message to a shape object.

Given a valid message, the object will take the appropriate action. Sometimes different objects might take different actions given the same message. For example, the area can be calculated for the rectangle and the circle object, though the method for calculating the area will be different for each.

Persistence

Persistence is the tendency for real world objects to remain in their place unless they are moved. In the computer model object representation, objects are not generally persistent. For example, if a computer is turned off before a document is saved, then part or all of the work will be lost. Word processing documents are not persistent by nature.

Ideally objects should be persistent so they model the real world. Object should save portions of itself without explicitly being asked to do so. Computers, however, are more efficient with non persistent objects. Creating persistent objects would decrease the efficiency and thus performance, so there is a trade-off to consider.

Building an Application with Visual Basic and MapObjects

There are several coding standards that can be used to increase efficiency, organize code in a logical manner and increase readability. Some standards described below, such as naming conventions, can be applied to any coding endeavor, be it an OOP or standard procedural application. Other standards, such as modularization and the use of classes are easier to implement in an OOP environment. In addition, although they are not hard and fast standards, the use of comments, user interface issues, and optimization techniques will greatly enhance the quality of the resulting code.

Standard naming conventions

Using standard naming conventions is very important, especially when more than one developer is involved. Naming standards reduces the ambiguity of source code, thus reducing the number of potential bugs. Naming standards also provide code that is easier to read and understand, thereby reducing the maintenance cost and time, and increasing the code reusability.

Hungarian notation is a widely used and easily understood naming convention. By using Hungarian notation for variables, one can easily ascertain the scope, data type and intended purpose of the variable. Readability is enhanced by organizing the naming convention so that the three portions of the variable name (scope, data type and intended purpose) are easily distinguished at first glance: A lower case prefix value at the beginning followed by an underscore denotes the scope, additional lower case values denotes the variable type, and the body of the variable begins with an uppercase letter. If the body is made up of more than one concatenated word, mixed casing should be used so that each word begins with a capital letter. The following example illustrates this concept with the variable name m_intSelectedFeatures.

Part Description Example
scope Describes the scope of the variable m_intSelectedFeatures
type Describes the data type of the variable m_intSelectedFeatures
body Describes the variable m_intSelectedFeatures

The scope of a variable is the level at which the variable is accessible. A variable declared in a function or subroutine is only accessible from that function or subroutine. A local variable of this sort does not require a scope prefix. Variables can also be local to the module or form, global to the project, or passed by reference or by value. Following is a list of the scope prefix designations.

Prefix Description
g_ Global
m_ Local to the module or form
{none} Local to the procedure
r_ Variable passed by reference
v_ Variable passed by value

Following is a partial listing of data types.

Prefix Description
dbl Double
int Integer
obj Object
str String
var Variant
lng Long
bln Boolean

The same convention of Hungarian notation can also be applied to the naming of forms, modules, objects and menu items. For example, form names can be prefixed with 'frm'. Module names can be prefixed as appropriate; with 'cls' or 'bas'. Objects such as command buttons, textboxes, and map displays can be prefixed with appropriate type prefixes, such as 'cmd', 'txt' or 'map'. For a complete listing refer to the Visual Basic Programming Reference. Again, the body of the variable name should be mixed case for readability and provide a description of the variable (i.e. SelectedFeatures).

Use of Comments

The importance of adding descriptive comments cannot be overstated. Comments are especially useful during development when more than one developer may be working with a particular module or procedure. It is recommended that each module have a comment header that describes the intended purpose of the module, descriptions of any variables local to the module and references to any global variables that are used. Comments should also be written for procedures, especially those that have variables passed in or values that it returns.

The Visual Basic and MapObjects syntax, combined with using Hungarian notation provides code that is fairly easy to understand. It is tempting to assume that the code is self explanatory. This may not always be the case when code is being shared. It may not even be the case when returning to the code several weeks later. Even a few well-placed comments will quickly increase the readability of code. This is especially important when using more complex constructs, such as arrays and collections.

Modularity

Modularity is a key concept in OOP. It is best realized when information is kept "private" to the module. Thus, when possible, it is best to avoid public variables. When public variables are used, the value may be modified during a particular subroutine, creating erroneous results when another subroutine uses the variable. Global variables also make the code less modular and more difficult to understand.

If there is a variable that is local to a module and it is used in several subroutines, the variable is defined local to the module in the General Declarations section. Usually associated descriptive comments would be placed with the variable definition. When the variable is used in a subroutine, the associated comments can either be rewritten, or the reader may have to refer to the definition to understand the variable. An alternate approach would be to define the variable the first time it is used. If a called subroutine requires the variable, it can be passed to the called subroutine. This produces code that is more modular and reusable. The code is easier to understand, and the relationship between modules is expressed more clearly.

Passing variables also aids in designing subroutines that are general; so that one subroutine can solve various problems of the same domain. For example, a module may have one subroutine that adds a point to a shapefile and another subroutine that adds a polygon to a shapefile. These two modules may be replaced by one subroutine that adds a feature to a shapefile. The point or polygon shape is simply passed to the subroutine where it is added to the specified shapefile. This approach has several benefits. First there is no duplication of code. Second, if the code needs to be modified, it will require modification in only one place.

User Interface Issues

There are several small yet very important details that should be tended to in creating an application. Though they may seem small and insignificant, paying attention to these details will create an application that conforms to standards of Windows based applications that is more intuitive and easy to use. The following guidelines are just a few examples of techniques to add polish to an application.

  1. On a form with more than one control, specify the TabIndex property so that the controls are activated in a logical order from the top to bottom and left to right. This is especially important if the user has numerous textboxes to fill in.
  2. Check for validity when text is input, and return a message to the user if the text is incorrect. Robust error checking routines will create a more "user-friendly" environment for the user.
  3. Enable controls only when using the control would be an appropriate action by the user. For example, if a form is designed to capture text input from the user to capture a latitude and longitude coordinates and display the point on the map, the form should have a cancel button, enabled at all times, and an OK button, enabled only when the textboxes have been properly filled in.
  4. Check spelling on command buttons, menu items, message boxes and help files. Include help files. This is easily incorporated with the Visual Basic environment and will create a professional looking application.

Optimization methods

Optimization techniques can be applied to both the front-end (GUI) and the back-end (code).

Front End (GUI)

Front-end optimization can be broken down into two categories: actual display speed and user-interpreted speed.

Actual display speed is affected by the speed in which windows are loaded and painted on the screen. As a Windows based application, Visual Basic has to load, unload, paint and repaint windows on a regular basis. The controls on your form can affect the speed of these operations. Thus it is best to not to use too many controls on a form. Especially for more complex controls, such as comboboxes and database controls, try to use one control for multiple purposes. If more than one control of the same type will need to be loaded simultaneously, place one control on the form and use a control array to create the remaining controls at run time.

User-interpreted speed can be affected by changing the programs order of events or the methods of execution. These techniques may not actually increase performance, but they give the illusion of faster performance. One technique is to load the most often used forms and keep them invisible until they are needed. This reduces the time required to load the form and its' related module. The MapObjects control can appear slow when displaying a large dataset. Increasing the map control's RefreshCount property will give the impression that the features are being drawn faster.

Back End (Code Optimization)

Appropriate use of variables will increase the speed and efficiency of the program. Avoid the use of variants. Variants require 16 bytes of memory, as opposed to a double, which requires 8 bytes and an integer, which only requires 2 bytes. When not in use, set string variables to zero length (i.e. set strMyVar = "") to save memory. Similarly set all other object pointers to Nothing at the end of the procedure. This also will free memory back to the system. In addition leaving pointers that do not point to anything can cause memory leaks.

There are several structural techniques that can be implemented to increase processing speed. Following is a list of several simple guidelines for the more common structures. For a more exhaustive list of guidelines for optimizing code, refer to any book on intermediate or advanced Visual Basic programming.

1. Avoid using a loop that must be evaluated each time through the loop, such as the following:

    For I = 0 to ListBox.Count
      intNum = ListBox.ListItem.Index
    Next I

The above loop can be changed so that the ListBox.Count value is only evaluated once

    intListCount = ListBox.Count
    For I = 0 to intListCount
      intNum = ListBox.ListItem.Index
    Next I

2. Try to combine several statements in the same line. For example, consider the following four lines of code:

    x = GetValue("Toolbar")
    If x = TRUE Then
      ToolBar.Visible = TRUE
    End If

This one line of code performs the same action:

    If GetValue("ToolBar") Then ToolBar.Visible = TRUE

3. Use the With statement to set multiple properties. This enables you to reference the same control in a more efficient manner. For example, the following code accesses the Label control three times in order to change its properties:

    Label1.Caption = "Label Caption"
    Label1.BackColor = Blue
    Label1.Top = 1200

A With statement increases the efficiency by accessing the control once

    With Label1
      .Caption = "Label Caption"
      .BackColor = Blue
      .Top = 1200
    End With

4. Use the For Each... Next loop when dealing with objects or collections. This method will always be at least as fast as the normal For... Next loop, and usually faster. It is also better suited for handling objects. The loop provides you with the current object in the collection and it is incremented automatically.

    Dim objCtrl as Control
    dim strCtrlName as String
    For Each objCtrl in Form1.Controls
      strCtrlName = objCtrl.Name
    Next

Conclusion

MapObjects is a powerful programming tool that can enable developers to incorporate mapping capabilities in their application. As the name implies, MapObjects is built upon an Object Oriented Programming paradigm. A basic understanding of OOP will enable programmers to realize the potential capabilities of MapObjects as a programming tool. By implementing standard development practices, programmers can take advantage of OOP constructs to build a robust application. In addition, standards enable teams of programmers to work efficiently together and encourage modularity and code reuse.

The coding standards described above; naming conventions, the use of comments, modularity, user interface issues and optimization methods are meant more as an introduction and starting point rather than an exhaustive listing. As programmers work together, they will devise their own standards and methodologies for their particular development goals.

References

Bettone, J.E, gifford, D.R., et al., "Tricks of the Visual Basic 4 Gurus", SAMS Publishing, Indianapolis, IN. 1996.

Montlick, T., "What is Object-Oriented Software?", Software Design Consultants, 1995.


Kristi Lombard
GIS Applications Programmer
TASC
12100 Sunset Hills Drive
Reston, VA. 20190
Telephone: (703)834-5000
Email: klombard@tasc.com