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.
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:
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.
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.
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:
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.
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.
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.
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).
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.
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.
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.
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:
The above loop can be changed so that the ListBox.Count value is only evaluated once
2. Try to combine several statements in the same line. For example, consider the following four lines of code:
This one line of code performs the same action:
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:
A With statement increases the efficiency by accessing the control once
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.
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.
Montlick, T., "What is Object-Oriented Software?", Software Design Consultants, 1995.