A user interface is an unusual sort of program because its success depends on emotional appeal. Emotional appeal doesn't ordinarily enter into our judgments of software. We judge a compiler according to more objective considerations, such as its speed and robustness and the speed and robustness of the code it generates. With interfaces, the rules are different.
The user interface is often the least sophisticated element of a program but the one users most care about. For the programmer, this means a relatively small amount of effort can make a program more appealing.
The biggest payoff, as software developers are discovering, is in graphics. A graphic interface by-passes the verbal and appeals directly to the visual. And anyone who has seen a video game knows how much more quickly visual information is assimilated. Who could play a real-time video game in which the state of the game was displayed as a screen of text?
This article discusses how to write graphic interfaces for LISP programs. It includes most of the code necessary to attach graphic objects -- dynamically updated graphic representations -- to LISP data structures. The code can be used to make a wide variety of programs more appealing to the front end of nearly any LISP program in a matter of hours.
This code runs under Common LISP with a very simple window system. If your LISP doesn't support windows, the code will work if you simply eliminate all references to them. It could easily be adapted to run under some other other lexically scoped LISP (such as Scheme), but it depends too heavily on lexical scoping to run under dynamically scoped dialects.
The Aim
This article will discuss graphic interfaces with an object-oriented flavor. To say that the things we're going to make will be objects is to say that:
- Each will be a discrete collection of LISP functions (or "methods") that entirely defines its behavior.
- Each will be an instantiation of some archetypical object.
- Each will act of its own accord; after we've defined an object, we won't have to think about it again; each object will update itself and, if necessary, any other objects, dynamically.
A concrete example will make all this clearer. Using the code given here, we will be able to define a type of graphic object called a "dial". We will then be able to make instances of dials as we need them, attaching them to LISP objects simply by saying attach, dial, and where we want the dial" attached: Once we have attached a dial to something, the dial will henceforth display its value. As the value stored in the LISP object changes, the needle of the dial will move automatically.