Kevin Howard and Robert J. Hallett Jr.
Robust Application Development in ArcView
ABSTRACT: As GIS becomes a more mainstream activity, applications
now require greater flexibility and functionality while maintaining simple-to-use
graphical user interfaces.This paper explores the challenges involved in
developing large, sophisticated ArcView applications that are designed
to work on a variety of platforms with various datasets and user requirements.
It will address:
-
Reducing development time.
-
Writing robust Avenue code.
-
Application portability across hardware platforms.
-
Accessing of user-defined datasets without requiring re-coding.
-
Eliminating hard-coded directory paths.
Introduction
Since the introduction of ArcView, users have requested increasingly sophisticated
applications which meet a number of basic criteria. The applications:
-
Must be robust, checking for errors both within the system and the data.
-
Can be setup on different hard disks and directories.
-
Are portable across Operating Systems.
-
Can access a variety of data across different computers and clients.
Unfortunately, it is extremely common when opening an application to encounter
a sequence of messages asking the user to re-establish the link between
the application and the data it needs:
This is because the paths to all of the data within the ArcView application
are saved as part of the Project file.
Once the application has started successfully, any number of fatal error
messages can occur, from the 'Nil Object' error:
Through the 'Unrecognized Command':
To the ever faithful, bad Script Parameters:
This document discusses how to avoid these error messages happening,
together with other points that should be taken into account when developing
a fully customized ArcView application that is robust and maintainable.
Structured Programming
When developing an application - regardless of the development environment
- a structured programming methodology should be followed. Although it
is not always necessary that the complete design cycle is followed for
every application (some systems may be too small to benefit from the time
invested in the full design process), several criteria must be taken into
account in the application design and implementation.
What is the Problem?
An application must correctly solve the problem it is intended to solve.
To fully determine the problem, the developer must talk with the client
(whether internal or external), and if possible the potential users, to
discuss their requirements and their expectations of the system. From this
discussion, as well as any supporting documentation, an application specification
document should be produced that clearly details the problem and proposes
a method of solution.
There are many cases where good applications have been developed that
do not solve the problem, or do not live up to the users expectations.
In both of these cases, the application (regardless of its technical merit)
will either not be used by the users, or will require extensive and costly
reworking.
Application Design
Although this document is not intended to address design methodologies,
some form of design analysis must be undertaken prior to the implementation
of a system. The design process should analyze the problem specification,
and produce a detailed design document giving:
-
A breakdown of the problem into sub-problems.
-
A schedule for implementing the solution.
-
Any critical components of the solution.
It should be noted that due to the simplistic nature of many ArcView applications,
and even many of the Avenue scripts within complicated applications, much
of the application design is pre-determined by User Interface requirements
(see below). Especially with ArcView applications, the User Interface is
the area where most of the design analysis should take place.
Reliability
Another criteria of a "well developed' application is that it must be reliable.
No significant program can ever be proven to be completely error free.
This is because the variety of combinations of test data required to test
a program completely is virtually infinite.
Hence, in the design phase all of the possible areas where reliability
may be a problem should be addressed. The results of this analysis will
either take the form of improved checking within the system, or (in the
last resort) the placing of restrictions on the applications performance
envelope. In all cases, the client should be made fully aware of the potential
problems, and the steps that have been taken to address them.
Maintainability
A third criterion of a well programmed application is that it must be easy
to read and easy to maintain. Programs are written to be read. In the past,
good programmers were often thought to be those who could write clever
and tricky code that ran in the shortest amount of time and used the least
amount of resources. Typically, once a program is put into production,
the clever and tricky code has to be maintained by another programmer.
(The maintenance of a program involves removing subsequent errors that
may be found and altering the code to reflect changes in the program's
specification). Today, maintenance costs can be significantly (orders of
magnitude) higher than the development costs. Hence, in an effort to minimize
costs, it is essential that easy-to-read and easy-to-maintain programs
are developed.
Graphical User Interface Design
GUI development is a complex and sophisticated area of system design. The
GUI should reflect the needs of the users (not the system designer or GIS
administrator) and reduce the learning curve associated with the system.
Modern computer systems succeed or fail by the quality of their user interface.
Regardless of how good the underlying functionality of the system is, if
the users do not find the interface intuitive and easy to use, the complete
system will not be used. Merely making cosmetic changes to a standard interface
and adapting existing functionality is no longer acceptable to most users.
This only succeeds in confusing the user. The customized interface should
add value to the system, and this must be apparent to the user in order
to make them want to use the system.
Modern user-interface design methodologies involve the users from the
initial design to final implementation. If one of these methodologies is
not followed, and the user is just presented with the prototype, it must
be designed by experienced individuals familiar with the design methodologies
and with users' "normal" requirements.
ArcView Menus
The menu system is the means by which the user interacts with the application.
The menu system should allow access to all of the functionality normally
available in ArcView, together with all of the customized functionality.
To minimize confusion, all of the customized options required for the
application should be made available on a customized ArcView menu system.
The series of customized menus (one or more for each ArcView document class)
should be the primary menus for the application.
This involves creating a customized menu system, as well as performing
small modifications to a copy of related native ArcView menu system. However,
at no time should the native ArcView menu system be altered. If a menu
system is to be customized (regardless of how minor the modification is),
a copy of the native ArcView menu should be taken and it is this copy that
is modified.
Toggling Menus
To minimize confusion, the native and customized ArcView menus should be
kept separate, with a method implemented which allows toggling between
the two menu systems. This can be either in the form of a toggle button
(which should be in the same location on both menus), or via a menu option.
In both cases, a small amount of customization must be performed on the
native ArcView menu system.
Dynamic Menus
The customized menu should be dynamic so as to reflect the data that has
been loaded into the application. This allows tailoring of the menu system
for specific instances of the application.
User Feedback
Throughout the ArcView application, feedback should be given to the user
as to the current state of the system. This can be in the form of using
the wait cursor (av.UseWaitCursor) if a
long process is being undertaken (i.e. query of an Oracle database), or
use of the status bar giving the percentage of the process completed (i.e.
accessing records in a table).
The status bar should also be used to provide useful information to
the user. This is useful as it does not delay the execution of a script.
This can be in the form of brief help information, the results of a calculation,
or details of the current process.
ArcView Project File
A Project is the file ArcView uses to organize and store information. Projects
keep any combination of related ArcView documents, Views, Tables, Charts,
Layouts, and Scripts, together in one file. A Project also stores references
to the spatial and tabular attribute information used within the system.
Hence, by opening and closing a single Project, the user can open or
close all of the components needed for a specific task or application.
For example, Views and related Scripts can be saved in a single Project
file. This ensures that when working with a View the required Scripts are
also available. In addition, Projects can be used to keep joined Tables,
or Tables and Charts together.
Although this seems the most logical way of storing the information,
it does create several problems.
-
Portability. When a Project file is saved, absolute directory paths
to all of the data are stored within it. Assuming neither the Project file
or any of the data change location, this is not a problem. However, if
the Project file were moved to a new location on the same computer, or
copied onto a new computer, when the Project is launched, the system asks
the user to specify the new directory paths to all of the required data.
Depending upon the amount of data required by the Project, this can be
a long and tedious process.
-
Project File Size. As each Project file contains references to every
document stored within it, the more documents, the larger the Project file.
This impacts upon the Projects loading time.
These problems can be minimized by storing the data references externally
from the Project file. This approach provides a number of advantages:
-
Rapid ArcView application development.
-
Customize the GUI's depending upon the loaded data.
-
Load spatial and attribute data, including joining data.
-
Create Themes from the defined data.
-
Improve Project loading speed by reducing the data processing required
at startup. For example, Themes does not have to be created (which may
require querying of the data) until they are requested.
Data Formats
Naming Convention
With the introduction of ArcInfo 7.0, Esri reformatted data workspaces
to conform to the MS-DOS standard of 8.3 filenames - up to an 8 character
name and a 3 character extension. This allows data to be transferred more
easily between UNIX-based and MS-DOS-based systems. Hence, any data tables
accessed or created should, wherever possible, conform to the 8.3 convention.
Spatial Data
Spatial data is at the heart of every ArcView application. Spatial data
is geographic data that stores the geometric location of particular features,
along with attribute information describing what these features represent.
Spatial data is also known as digital map or digital cartographic data.
With the introduction of ArcView 3.0, spatial data can be stored in
several different formats. Each format has advantages and disadvantages.
Format |
Advantages |
Disadvantages |
ArcView Shapefile |
Comparatively small size.
Comparatively fast drawing speed. |
Can only have one feature type per file
Cannot be used with route systems |
ArcInfo Coverage |
Fully compatible with ArcInfo. |
ArcView cannot repair an ArcInfo workspace.
So if one coverage becomes corrupted, the whole workspace has to be replaced. |
ArcInfo Librarian |
Allows coverages to be stored as tiles.
Setting the View's Area of Interest means only the tiles required for
the View are accessed, improving speed. |
Difficult to implement. |
ArcStorm |
Improved version of ArcInfo Librarian. |
Latest version unstable. |
Note: ArcInfo 7.0 has routines for converting from shapefiles
to coverages (shapearc) and vice-versa
(arcshape).
Wherever possible, it is recommended that shapefiles are used as the
standard spatial data format. If ArcInfo coverages are to be used, each
separate spatial layer should be stored in its own workspace, so if it
becomes corrupt, only one spatial layer needs to be replaced/repaired.
ArcView can also display AutoCAD drawings and Image data (i.e. satellite
images, air photographs and other remotely sensed or scanned data). The
valid image formats include ArcInfo GRID data, TIFF, Windows Bitmap (.bmp),
TIFF/LZW compressed image data, and Sun rasterfiles.
Attribute Data
Native ArcView can access three different types of attribute data.
Format |
Advantages |
Disadvantages |
Tab or comma Delimited Text |
Virtually all applications (Word processors,
spreadsheets etc.) can access/display
Easily understood format |
Cannot edit the data within ArcView, without
exporting it to INFO or dBase format |
INFO |
More secure than other file formats (tables
encoded in workspace) |
Can not delete INFO tables, although they can be overwritten
If an INFO table becomes corrupted, the whole workspace has to be replaced
Proprietary file format |
dBase |
Industry-wide standard format
Native ArcView format
Can be accessed from other applications |
Can be accessed from other applications - users
can change data |
Note: ArcView cannot directly access fixed-length ASCII text
files. These must be pre-processed into one of the known formats before
the data can be accessed.
ArcView can also connect to database servers, such as Oracle, Ingress
or Sybase, and retrieve records using SQL queries. For details on this
process, refer to the ArcView Help section entitled "Connecting to a database
to create a table", "Setting up a database connection with ODBC" (MS-Windows)
and "Logging into a database with the Database Integrator" (UNIX).
Help Files
All ArcView projects should have on-line Help. This documentation can be
based on the User Guide and other technical documents written for the project.
The method of creating the Help files depends upon both the operating
system and the required sophistication of the Help system.
MS-Windows 3.1x, NT and '95
Microsoft (and other compiler developers) distributes a Help file compiler
called WinHelp. This processes a file into the required format to be displayed
by the Windows Help system. However, there are several methods for generating
the initial file.
ArcView Method
ArcView contains an internal Help file generation system that uses control
codes within a rich text format (RTF) file. Refer to ArcView for Windows
on-line Help file under the topics "Building You Own Help File",
"Building context-sensitive help in ArcView for Windows" and "Running
a script from a help file".
Word Processor Method
There are many utilities available (both commercially and share/free-ware)
which can generate a Windows Help file from a Word processing document.
This has the advantage that the written documentation will already exist
in a word processor document, although because it is outside of the ArcView
system, it is unlikely that Scripts could be run directly from the help
file.
UNIX Method
Creating Help files for use with ArcView for UNIX requires use of an internal
ArcView Help file generation system. For details, refer to the ArcView
for UNIX on-line Help file under the topic "Building you own Help file".
Extending ArcView
Extension Methods
The basic functionality of ArcView can be extended using a number of different
systems. Each one has a different level of sophistication with a proportional
level of effort to implement. The actual extension method to use depends
upon the application, although there are a number of factors to take into
account:
-
Is the ArcView application to work on multiple operating systems?
-
Can the standard ArcView documents (View, Table, Chart, Layout or Script)
be adapted to provide the required functionality?
-
What level of sophistication is required?
-
Is a large amount of data to be passed to the extension application?
-
Is a response required from the extension application?
"Command-line" Interface
The simplest way of extending ArcView is to call an external program by
using the System.Execute Avenue command.
While this method works on any operating system for which ArcView is available,
it lacks control since no parameters can be returned to the application.
"Table" Interface.
This method is similar to the command-line interface apart from the fact
that all of the data being passed is written to tables which are processed
by the external program. While it is still relatively simple to implement
and works on all operating systems, it still requires some command-line
parameters to be passed, as well as extensive data checking in the creation/reading
of the table.
Neuron Data
Before the introduction of ArcView 2.1, Neuron Data Open Interface was
virtually the only viable method for producing sophisticated applications
for use with ArcView. However, the current ability to use DDE and DLL as
well as ArcView Extensions has negated the requirement to use this extension
method.
Dynamic Data Exchange (DDE)
DDE can be used to inset data into a third-party application (i.e., MS-Excel).
This method requires a DDE server to be running upon the third-party application.
There are also a limited number of data types that can be passed with a
relatively slow data transfer rate. It is also complicated to implement
and requires different implementations for different operating systems.
Dynamic Link Libraries (DLL)
Use of DLL's provides the closest integration between ArcView and the extension
application, with a fast transfer of a wide variety of data types. However
similar to DDE, it is complicated to implement and requires different implementations
for different operating systems.
ArcView Extension
Since the introduction of ArcView 3.0, native Extensions that use Avenue
code can be developed. Use of ArcView Extensions provides a module environment
for developing ArcView applications by grouping related functionality within
one Extension. However, care must be taken when developing the Extensions
so that they do not interfere with the rest of the application. This may
happen if the Extension resets global variables or the object tags on documents.
If variables need to be stored, each Extension maintains a Dictionary that
can be accessed via the aExtension.GetPreferences.
Refer to the Extension Discussion document in the ArcView on-line Help
file.
DDE/DLL Development Environment
Creation of DLL's (or any of the other extension methods) can be performed
in a number of development environments. The choice of development environment
depends upon the type of application, the specific operating system, and
whether the code has to be portable across operating systems.
It is recommended that the preferred development environment will be
a high-level programming language (C/C++ or Visual Basic) together with
a cross-platform set of GUI development libraries.
Programming Style
The way a programmer writes code is as individual as the way that they
talk. The programming style adopted should be flexible enough to take into
account these programmer preferences. However, the code produced should
have clear and concise comments and make good use of indentation so that
another programmer should easily be able to understand a code fragment.
Whatever style the programmer adopts, they should remain consistent throughout
the code. For example, the same number of indentation characters should
always be used, and meaningful names should always be used to describe
data items and functions.
Naming Conventions
Avenue Scripts
To help in the process of identifying the purpose of a function and for
grouping functions into similar areas, a standardized naming convention
should be adopted. Restrictions on the naming convention depend upon the
code type being written, the hardware type and portability requirements.
As there are few length restrictions on Avenue script names, the script
name should give a fairly detailed idea as to its function. Scripts normally
fall into 3 main categories:
-
Scripts that would be generally useful across different Projects.
-
Scripts related to a specific ArcView document.
-
Scripts that are specific to one Project.
These types of scripts can use the following naming convention.
GIS/Trans : Script Name
Document Name : {Menu Path}.{Type of Event}
App : Script Name
In defining the menu path, a delimiter should be used. It is recommended
that the pipe character (|) should be used for this function.
Name |
Description |
Custom View : Area | State.Click |
Associated with the State option under the Area
option respectively of the Custom View GUI. |
Custom View : Area | State.Update |
Associated with the State option under the Area
option respectively of the GIS View GUI. This script is called when the
option receives the Update event from the system. |
Custom View Button : Toggle GUI.Click |
Associated with menu button for swapping the
active GUI to the alternate GUI. The script is run when the button is clicked. |
Custom View Tool : Identify.Click |
Associated with the Identify tool on the Custom
View. The script is run when the tool is clicked. |
Custom View Tool : Identify.Apply |
Associated with the Identify tool on the Custom
View. The script is run when the tool is applied. |
GIS/Trans : Get Theme Type |
Utility script that finds the type of a theme.
This is of general use (i.e. should be part of a software library) so has
the 'GIS/Trans' prefix. |
App : Startup |
The Project startup script. This is implementation
specific so has the prefix App. |
Local Variables
Although a developer may believe they are saving time by using short or
cryptic variable names, in the long term this is a incorrect belief. Variable
names should clearly indicate the purpose of the variable.
Esri has defined a convention as to the naming of variables created
directly from Avenue classes.
-
Unique variables. These are all variables that contain a unique
example of a particular class.
Examples:
theProject = av.GetProject
theDoc = av.GetActiveDoc
-
List variables. Many Avenue scripts return a homogeneous list of
a particular class. The variable should be prefixed by 'the'
and the class name should by plural.
Examples:
theDocs = av.GetDocs
theThemes = theView.GetThemes
-
Loop variables. If a script has to process a homogeneous list, the
loop variable will contain many variables of the same type. The loop variable
should be prefixed by 'a' and the class name should be singular.
Example:
theThemes = theView.GetThemes
for each aTheme in theThemes
aTheme.SetActive(FALSE)
end
Global Variables
Global variables should use the same naming conventions as local variables,
with the addition of the prefixed "_" character.
Traditionally, due to the way ArcView processed scripts at startup,
all of the global variables had to be placed in one script which is named
to be the first script in alphabetical order. For example, the script could
be called aaGlobals. With the introduction
of ArcView 2.1, this restriction was removed. However, all global variable
definitions should be kept in one script.
Script Headers
For each script, a header must be included to give all of the relevant
details relating to that function. From this header, a programmer unfamiliar
with the code should be able to understand the purpose of the function,
together with the parameters and data that it requires to execute correctly.
However, the script name should give a good idea as to the purpose of
the script. This is especially the case with Avenue scripts as described
above. Also as many Avenue scripts are of a simplistic nature, the time
expended on creating the header may never be recouped in future use of
the code.
Although the actual headers will vary with the programming language,
certain flags should be reserved for use in all headers. This means that
set names are used for specific header fields, and has the added benefit
that programs could be written that could automatically generate documentation
form the source code. This process can be partially automated by changing
the default ArcView project to always create a customized script.
Flag |
Name |
Description |
N |
File name |
|
C |
Copyright |
|
D |
Description |
Description of the function purpose |
P |
Parameters |
List of any arguments that need to be passed
to the file. |
R |
Returns |
The object that is returned by this Script |
G |
Global Variables used |
List of any global variables used. Also states
if the variable needs to be predefined or if it is set during the function
execution. |
E |
Called Scripts |
List of calls that the function makes. |
S |
Called By |
List of other functions that call this function. |
K |
Keywords |
Space-delimited list of keywords for searching
purposes. |
O |
Operating system dependencies |
Any dependencies that the function has on the
operating system. |
H |
History |
History for the function. Include items such
as version number, date, author and a brief message of changes performed |
Comments
In commenting a piece of code, the programmer must weigh the time required
to fully comment the code, against the time it would take a person who
is unfamiliar with the code to understand it without comments.
The comments should be clear and concise!
Appendix A gives examples of commenting an Avenue script.
Indentation
Good use of indentation should be used to help identify the flow of the
script. Consistent indentation (i.e. number of spaces) should always be
used. It is recommended that a 2-space character indentation is used. This
size of indentation is partially imposed by ArcView as this is the indentation
used by the 'Shift Lines Left' and 'Shift Lines Right' Script Editor buttons.
To help reduce the number of levels of indentation, care should be taken
to exit a script once an error has occurred or no further processing is
required. A good example of this is a MsgBox
that allows the user to press Cancel.
Example:
' Performing an inappropriate
check requires the remainder of the script to
' be indented
theResult = MsgBox.ChoiceAsString(theChoiceList,
"Select the required choice",
"Title")
if (nil <> theResult)
then
' Perform
processing within the indentation
:
:
end
' Careful checking of
results remove a level of indentation
theResult = MsgBox.ChoiceAsString(theChoiceList,
"Select the required choice",
"Title")
if (nil = theResult)
then
return nil
end
' Processing can now be
performed without requiring indentation
This correct checking of returned values also means that the processing
level is reduced as the remainder of the script does not have to be parsed.
Writing Robust Avenue Code
Whenever code is written, it should be written so that it will continue
to function (i.e. not crash) even if invalid data is supplied to it, or
the code is trying to execute with the system in an unexpected state.
ArcView Versions
With the release of ArcView 3.0, there are 4 different versions of ArcView
currently in use - v1.0, v2.0, v2.1x and v3.0x.
To combat incompatibilities between the different versions, Esri has
included an av.GetVersion command which
returns the version number plus any patch letter code (i.e. "2.1b").
Therefore, any version specific code must be bracketed by this command
Example:
if ("2.1" = av.GetVersion.Left(3))
then
' Do v2.1x
specific code
else
' Do v3.0
specific code
end
Note: This command was not available in v2.0. Hence, the first
knowledge the application would have that it is running on version 2.0
is when it causes a system crash on the av.GetVersion
command!
Note: The if.then.else statement
should be written in order of version number. This means that if a command
does not change in a future version, no Avenue code will have to be altered.
Note: The av.GetVersion command
returns the full ArcView version. Hence, to perform version specific code,
the left-most three characters need to be compared.
Returned Values
When a Script completes execution either successfully or with an error
condition, a value is returned to the calling Script. This value should
indicate the success or failure of the Script. By Avenue convention, when
an error occurs nil is returned to the
calling Script. However, the nil value
is returned if a Script is exited without a return call. Hence, even if
a Script does not return an object, it should return a non-nil value (TRUE)
to indicate it executed successfully. The type of returned value should
depend upon a number of factors.
-
The Script completed successfully
-
The severity of the error condition
-
Whether the current program branch should continue
The proposed types of returned values are as follows:
-
Boolean. No Avenue object is returned so TRUE is returned if the
script terminated successfully, FALSE otherwise.
-
Numeric Error Code. If a script does not return an Avenue object,
but the state of termination of required, a numeric error code can be returned.
The value 0 should indicate success, whilst
errors should be indicated by various negative values.
-
Avenue Object. If on successful termination, a script returns an
Avenue object, a error condition should be indicated by returning a nil.
Although numeric error codes could be returned for failure, the calling
script must filter the returned value.
Checking Returned Values
Throughout Avenue code, the Scripts frequenty ask objects to return both
values and pointers to other objects. In most cases, it can be assumed
that these operations will succeed, especially when interrogating standard
objects.
Example:
theProject = av.GetProject
theFTab = theTheme.GetFTab
However, in some cases the Script may be asked to find a field in a
Table, open a disk file, or process the response of a message box. In all
cases, the returned value may be incorrect (null)
or invalid (nil). The response to these
statements must be checked.
Example:
' Access the field XYZ
in the FTab
theField = theFTab.FindField("XYZ")
if (nil = theField) then
MsgBox.Error("Failed
to find field 'XYZ' in table '"+theFTab.GetName+"'",
Script.The.GetName)
return FALSE
end
' Select one of the entries
from the Choice List
theChoice = MsgBox.ChoiceAsString(theChoiceList,
"Select the required choice",
"Title")
' If Cancel was pressed,
then nil is returned
if (nil = theChoice)
then
exit
end
Clear Error Messages
The above example highlight the need for clear error messages, for both
the developer and the user. This not only assists the programmer in tracking
down errors but also gives the user a clear indication as to the position
of Script errors.
The developer should also pick the level of the error and display the
correct ArcView dialog.
-
Information Dialog. Should be used when the system has to communicate
information to the user, but can continue.
-
Warning Dialog. A more serious error has occurred, but the system
can continue with possibly some limitations.
-
Error Dialog. A fatal error has occurred, and the system cannot
continue in its current state. Processing will be terminated. It is advised
that the name of the Script that the fatal error occurred within is used
as the title for the dialog. This is help is locating of the error.
Note: It is not possible to obtain the "stack" of calling Scripts
so as to give more informative error reporting.
Checking Script Parameters
If a Script is called with a set of parameters, these parameters must be
parsed to check they are of the correct format. This traps a number of
problems (too few/many parameters, incorrect classes etc.) that would cause
problems later in the Script.
Example:
' It is assumed that
a Script exists that takes 2 parameters:
' - the parameters passed
to the Script (as a list)
' - a list of the required
classes for those parameters
if (av.Run("App : Verify
List", {SELF, {String, Theme, FTab}}).Not)
MsgBox.ListAsString(SELF,
"Invalid Parameters",
Script.The.GetName)
exit
end
Note: In the above code fragment, the message gives the name
of the script that the error occurred within as its title. This gives the
developer an idea as to where an error has occurred.
Checking the State of the System
Many Scripts require the ArcView system to be in a particular state (i.e.
a View is the currently active document) for them to function correctly.
It is a big assumption that because a Script is attached to a View GUI,
that the active document is a View. For example, when the system is changing
state (i.e. displaying a Table of data associated with a Theme), as many
Scripts are event driven (i.e. update scripts) a View update Script may
be called when a Table document is active.
This problem also arises when an error occurs in an update Script. ArcView
immediately displays the offending Script, so the active document is now
a Script Editor (SEd). However, the update event still has to be processed
by all of the other update Scripts.
Hence, whenever the state of the system is requested, the response must
be checked.
Example:
theActiveDoc = av.GetActiveDoc
if (theActiveDoc.Is(View).Not)
then
MsgBox.Error("The
Active Document is not a View",
Script.The.GetName)
exit
end
Use of Menu Update Scripts
Many options are only valid when the system is in a particular state. For
example, many options work on the active Themes in a View, while "Show
Table" is only valid for Feature Themes in the View, not Image Themes.
Checking for these conditions can be performed by the Script associated
with the Click/Apply operation. However, by performing the checking in
the Update script, the menu option can be enabled/disabled as appropriate.
This gives several benefits:
-
Stops the user selecting the option when the system is in the wrong state.
-
Gives a visible indication of the valid operations.
-
Minimizes the error checking in the Click/Apply script. (i.e. the script
does not have to report to the user that the system is in an incorrect
state for the requested operation)
Variable Comparison
The above examples also show the correct method for checking values. This
is namely that the constant should be on the left of the equality sign.
This has the benefits that:
-
There is no confusion as to whether the variable is being set.
-
If a coding error has been made (i.e. the if construct is omitted), the
ArcView syntax checker will produce an error instead of trying to interpret
the line incorrectly.
Example:
theChoice = nil
' This will set the variable theChoice to nil
nil = theChoice
' This will produce an interpreter error
Note: Although the proposed method of variable comparison is
not strictly necessary in Avenue, it is good practice to use one standard
across programming languages. Hence, when a programming language is used
that has different comparison and setting symbols (i.e. Pascal (=
and :=) and C/C++ (==
and =)), the proposed comparison
method can still be used.
Use of Example Datasets
While it is generally agreed that using a reduced dataset during the coding
process has many benefits, care must be taken during this process not be
develop code that is optimized for the reduced dataset. This may manifest
itself in problems displaying large datasets (i.e. landuse), or the use
of Theme Legends that may be OK at a "zoomed-in" level but may not be correct
when looking at the whole dataset.
Use of the 'Tab' character
While most programming languages treat Tab characters as "white space",
just like "space" and "carriage return" characters, strange things can
happen if you insert tabs in code. Such bugs can be especially difficult
to detect because Tab characters cannot easily be seen in the code.
Conclusion
By using a consistent set of standards, ArcView developers can build upon
the work undertaken for previous applications creating:
-
A library of routines/scripts to be used for future development.
-
Other scripts that can be shared more easily between ArcView Project configurations.
-
An improved standard for written Avenue code.
-
Better designed Projects.
-
Cross-fertilization of ideas.
Appendix A - Example Avenue Script
This script shows how the parameters to a script can be parsed to check
for problems.
'N Name
: ADM : Verify List
'
'C Copyright : (c) GIS/Trans,
Ltd. 1997
'
'D Description : Verifies a set of Objects
in a List against a set of Classes in a List. The two
'D
: Lists must be the same size.
'
'P Parameters : List - List of Classes
'P
: List - List of Objects
'P
: Boolean - TRUE if errors should be displayed in a MsgBox. FALSE otherwise
'
'R Returns : Boolean
- TRUE if the List of Objects is valid against the List of Classes.
'R
: FALSE otherwise
'
'E Called Scripts : ADM Message : Set Error
'
'S Called By : ADM Message
: Display
'S
: ADM Message : Get
'S
: ADM Message : Get Level
'S
: ADM Message : Get Title
'
'K Keywords : Parameters
Verify
'
'O OS Depends. : None
'
'H History : K
Howard 1-Jan-97 Initial Coding
'
' Check to make sure that a list of 2 items as been passed
if (nil = SELF) then
av.Run("ADM Message : Set Error", {"nil pointer passed to
function",
Script.The.GetName})
return nil
end
if (SELF.Is(List).Not) then
av.Run("ADM Message : Set Error", {"SELF object is not a
List - it is a '"+SELF.GetClass.GetClassName+"'",
Script.The.GetName})
return nil
end
' Retrieve the parameters from the list
parametersList = SELF.Get(0)
if (nil = parametersList) then
av.Run("ADM Message : Set Error", {"Parameters List pointer
is nil",
Script.The.GetName})
return nil
end
if (parametersList.Is(List).Not) then
av.Run("ADM Message : Set Error", {"Parameters List is not
a List - it is a '"+
parametersList.GetClass.GetClassName+"'",
Script.The.GetName})
return nil
end
' See how many parameters are passed. If there are only two, set
the
' report errors flag to TRUE
if (3 = SELF.Count) then
reportErrors = SELF.Get(2)
else
av.Run("ADM Message : Set Error", {"There is an invalid
number of parameters ("+SELF.Count.AsString+
") in the passed list",
Script.The.GetName})
return nil
end
' Get the passed class definitions
classList = SELF.Get(1)
if (nil = classList) then
if (reportErrors) then
av.Run("ADM Message : Set Error", {"Class List
pointer is nil",
Script.The.GetName})
end
return nil
end
if (classList.Is(List).Not) then
if (reportErrors) then
av.Run("ADM Message : Set Error", {"Class List
is not a List - it is a '"+classList.GetClass.GetClassName+"'",
Script.The.GetName})
end
return nil
end
' Check to see that there is the the same number of passed parameters
' as there are class definitions
if (parametersList.Count <> classList.Count) then
if (reportErrors) then
av.Run("ADM Message : Set Error", {"Number of
parameters ("+parametersList.Count.AsString+
") and classes ("+classList.Count.AsString+") do no match",
Script.The.GetName})
end
return nil
end
' Check each parameter against it's class definition
listSize = parametersList.Count
for each i in 0..(listSize - 1)
aParameter = parametersList.Get(i)
aClass = classList.Get(i)
if (nil = aClass) then
if (reportErrors) then
av.Run("ADM Message : Set Error",
{"Failed to get Class "+i.AsString+" from Class List",
Script.The.GetName})
end
return nil
end
' Check to see parameter is of the correct class
if (aParameter.Is(aClass).Not) then
if (reportErrors) then
av.Run("ADM Message : Set Error",
{"Parameter "+i.AsString+" is not of type '"+aClass.GetClassName+"'"+nl+
"It has Class '"+aParameter.GetClass.GetClassName+"'",
Script.The.GetName})
end
return nil
end
end
' The parameter list has been successfully verified
return TRUE
Kevin Howard
Senior Analyst
GIS/Trans, Ltd.
675 Massachusetts Ave
Cambridge, MA 02139
Tel: +1 (617) 354-2771
Fax: +1 (617) 354-8964
E-Mail: khoward@ma.gistrans.com
WWW: www.gistrans.com
Robert J. Hallett Jr.
Analyst
GIS/Trans, Ltd.
675 Massachusetts Ave
Cambridge, MA 02139
Tel: +1 (617) 354-2771
Fax: +1 (617) 354-8964
E-Mail: rhallett@ma.gistrans.com
WWW: www.gistrans.com