Objects in a Graphical User Interface


A graphical user interface can be a complex organization of a variety of different kinds of objects. The following sections describe some types of objects that are common to most graphical user interface programs. Of course, each such program has more types of objects that are specialized to the objectives of the program.

Visual Components

The most conspicuous objects in a Graphical user interface are various kinds of visual components. A visual component is responsible for creating a visual appearence the reflects the state information held by the component.

Several kinds of visual components can be shown in the applet below. The combo box at the top selects which one is shown. The title shows the class of the component.

</COMMENT>

Visual objects maintain whatever state is necessary for a correct display under any circumstances. For example, labels only have to remember their text, but buttons must be able to display itself in two ways, depending on whether or not a mouse button is pressed on it.

All of the components can be manipulated in some way except for the label. These other components can have window focus, which usually is made apparent by a change in the component's visual appearence. Many of the components also maintain state about selections made by a user.

Containers and Layout Managers

You can also have objects that represent groups of visual components. In the applet below, there are 23 buttons arranged in groups. All of the buttons are identical except for their names. The groups are more conspicuous if you resize everything by dragging the mouse in the applet's display area.

</COMMENT>

Each of the groups is held by a container object. A container is responsible for keeping track of components within a display region, but has no visual appearence of its own except for a background color. You can see the approximate bounds of the different containers in the above applet by selecting the "Line" menu item in the "Border" menu. Containers are a special kind of component. This allows you to put containers inside other containers.

In Java, there are two general types of containers: JPanel objects and content panes of top-level windows. In addition, there are several specialized types of containers such as split panes and tabbed panes.

One reason for grouping components is to get control over the layout. You probably noticed that when the outermost container is resized, the components in the four inner containers move and resize in four different ways.

Containers do not themselves control the location and size of their components. They delegate this responsibility to a layout manager. Each of the four inner containers is the same kind of container, but they use four different kinds of layout managers. You can see what kind of layout manager each container is using by selecting the "Titled" menu item on the "Borders" menu.

Graphics Objects

Many applets and stand-alone applications need to do custom graphics. A graphical user interface toolkit will usually provide graphics objects that are responsible for providing the capability of drawing various kinds of geometrical objects. The following applet showcases the graphics objects in Java's class libraries.

</COMMENT>

Actually, there is a graphics object attached to each visual component. For most of the components, the use of the graphics object is built in - that is how components set up their appearence. The container that was used in the previous applet, however, has no appearence of its own except a background color. Thus it it an ideal component for doing custom graphics. In Java, the class for this container is the JPanel class.

Listeners

A graphical user interface toolkit needs some mechanism for customizing behavior. Although a toolkit component may have complex ways of changing its appearence to reflect the focus, selections, and other user input, it cannot be expected to provide all of the behavior needed by complex programs.

To allow programmers to control the behavior of their user interfaces, toolkits generally allow the programmer to register listeners on the various components. A listener is often just an object that encapsulates a single method.

For example, buttons uses a type of listener called an action listener. This listener implements a single method called actionPerformed(). A programmer writes an implementation for this method and registers the listener on the button. Whenever the button is clicked the actionPerformed() method is automatically invoked.

Text fields also use action listeners. They invoke the actionPerformed() method whenever the user hits return in the text area. The action listener for the text area in the graphics applet triggers a cascade of messages. The listener itself just tells the graphics drawing panel to update itself. The draw panel then sends a sequence of messages back to the control panel to find out what to draw, where to draw it, how big, and anything else that might be relevant. After all the information is gathered the draw panel sends an appropriate message to its graphics object. This message is displayed in the title of the draw panel.

Top-Level Windows

Last, but not least, there are top-level window objects. These objects are responsible for initiating the execution of a program. They also provide a top-level container for all of the visual objects in a program.

In Java, there are two types of graphical user interface programs: applets and stand-alone applications (or just applications). Applets are executed from a browser and applications are executed directly from a Java virtual machine.

There are two things that must be done to get either an applet or an application running: a top-level window object must be created and code must be executed that assembles the visual components into a hierarchy of containers, sets up layout managers, and registers listeners.

For applets, the browser constructs the top-level window. It knows what class of object to construct because that is specified in the HTML file that the browser reads. The class is expected to be a subclass of the JApplet class (for Swing applets) which implies that the class defines an init() method. This is the method that assembles the visual components, sets up layout, and registers listeners. The applet begins execution when the browser instructs its Java virtual machine to invoke the init() method. The browser determines the location of the applet window, and sets its size using the size specification in the HTML file.

Applications are started up when the java command is given to the command interpreter of the operating system. A class is specified as a parameter for this command. When the java command is executed, it starts up a Java virtual machine, then invokes the main() method of the class. For a Swing graphical user interface application, the class is a subclass of the JFrame class. The main() method is written to construct an object of the class and set its location and size. The class constructor contains the code that assembles the visual components, sets up layout, and registers listeners.

After the applet init() method or application constructor are invoked, nothing happens until the user does something. Then the listeners take over, each implementing behavior appropriate to the user's activity.

When applets or applications get too large, it is essential to control the complexity of the applet init() method or the application constructor. This can be accomplished by delegating portions of the work to helper methods and by careful design of auxilliary classes to absorb some of the responsibilities. In a well designed program, none of the classes or methods is very large. Each does a limited, well-defined portion of the work. Otherwise, it is difficult to keep track of what is going on, and difficult to determine the cause of bugs. And when programs grow (successful ones always do), a good design makes a tremendous difference in the amount of work required to make changes.

The same design principles apply to the listeners. They are often designed with a single line of code that just delegates behavior to an object from a class with more expertise in dealing with the desired kind of behavior. When the desired behavior requires something beyond the expertise of the object, it in turn delegates to another object that has the necessary expertise.