The Java GUI Environment

Java provides a platform-independent GUI toolkit that one can use to create interactive, graphical applications. The initial Java release contained a toolkit called the Abstract Window Toolkit, which is frequently referred to as the awt. This initial toolkit was awkward to use in practice so later releases of Java have contained a new toolkit called the Swing Toolkit and the components in the toolkit are typically referred to as Swing components. You will sometimes see the Swing classes referred to as JFC classes, which stands for Java Foundation Classes. Your program can access classes from these two toolkits using the following import statements:

import javax.swing.*;
import java.awt.*;

Swing is built on top of the awt and Java programs still make use of awt components, especially the awt event handling mechanism. We will talk more about event handling in later lectures.

Creating Java GUIs

One can use Java to create either a standalone application or an applet. A standalone application is meant to be invoked from a shell or using Java's Web Start Application whereas an applet is meant to be invoked from within a browser. Standalone application are created by using the JFrame class and applets are created by using the Applet or JApplet class. The JFrame class creates a standalone window whereas an Applet class creates an embedded window in a browser.

The principles of window layout and management apply to both JFrames, Applets, and JApplets so the following discussion will use the generic term window. A programmer displays objects in a window by creating container objects, adding graphical components to these container objects, and then adding the container objects to the appropriate window. Graphical components are typically Swing objects, such as menus, radio buttons, labels, and text fields. Java containers extend the class JComponent so that containers as well as components can be added to containers.

The manner in which graphical components are laid out in a container is determined by a layout manager. Java provides a number of pre-defined layout manager classes that employ different algorithms to lay out the components of a container. A programmer creates an instance of the appropriate layout manager and then adds it to a container.

The most commonly used containers are JPanels and JScrollPanes. These containers basically provide an empty canvas for displaying objects. Every window has a JPanel associated with it that is created by Java when the window is created. This JPanel is called the ContentPane and can be accessed using the getContentPane method. Typically your program will add containers and Swing components to the ContentPane. Click here to see a tutorial for a simple SwingApplication that illustrates what we've discussed thus far.

Creating Custom Graphics

Swing components provide a set of GUI-independent objects for controlling an application and for inputting parameters to an application. They also provide a way to display the output from an application. However, we often want to display the application's data in custom ways that cannot be drawn with Swing components. For example, if we are designing a drawing editor, we cannot use Swing components to draw the rectangles, circles, and lines that are needed to draw diagrams. Similarly, if we are creating a circuit editor, we cannot use Swing components to draw the elements of the circuit.

Java allows a program to draw its own custom graphics by overriding the paintComponent method that is associated with every JComponent (JComponent is the base class for all the Swing objects and Swing containers). Typically a program will choose to draw on a JPanel, so the program will create a class that extends JPanel and then override the paintComponent method. The paintComponent method is declared as follows:

protected void paintComponent(Graphics g);

The Graphics object is an object that has a large number of methods for drawing the outlines of graphical shapes, such as rectangles, lines, and circles, filling shapes with colors, drawing strings, setting background and foreground colors, setting fonts, and doing many other things. The Graphics class was in the first Java release but it was pixel-based, which made it difficult to port applications to computers with different screen resolutions. As a result, the Java2D package was developed for later Java releases and provides a Graphics2D class that provides a more screen-independent way of drawing objects by allowing objects to be drawn in something called application coordinates and then transformed via affine transformations to screen coordinates. The screen resolution can be obtained by querying a particular Java-provided global object and this screen resolution can be integrated into the transformations. All Graphics objects can be downcast to Graphics2D objects.

When you create custom graphics, you considerably complicate your life since you must deal with a host of issues that Swing components normally handle for you. The two major issues that you must deal with are:

  1. Mouse and keyboard handling: Swing components provide all the code required to handle mouse and keyboard events. By contrast you must write mouse and keyboard event listeners to handle events when you create custom graphics. Typically you will need to implement some type of data structure that keeps track of the objects that you have drawn on the screen so that you can determine over which object a mouse or keyboard event is occurring.

  2. Display management: Your code is responsible for both notifying Java of when you want your custom graphics redrawn (you do this using the repaint command) and for redrawing the graphics when your paintComponent method is called. If your application contains a significant number of graphical objects, you might need to implement an incremental redisplay algorithm that only redraws objects which intersect the damaged portion of the screen. In this case you will need to maintain data structures that keep track of the locations of all the objects you have drawn so that you can determine which ones intersect the damaged region.

One problem that novice Java programmers commonly make is that they try to invoke drawing commands outside of paintComponent. Doing so can lead to unpredictable results. The only time that it is safe to draw anything is when you are inside paintComponent. If you want a portion of the display redrawn, you must call repaint and wait for Java to call your paintComponent method.

Event Handling

So far we have discussed how you output graphics to the screen. The other half of the equation is how we get input from the user. The way input is accomplished in Java and in other languages is for various resources, such as the mouse and keyboard, to generate events. These events are directed to the appropriate window and the application is expected to handle them.

Java provides a useful mechanism called a listener model that allows components and containers to register an interest in an event. When a window receives an event, it checks to see which objects are interested in the event and notifies the object by calling an appropriate method associated with the object and passing in the event object as a parameter.

Java pre-defines a large number of events, such as MouseEvents and KeyEvents, and for each event it provides a listener interface. Each listener interface declares a set of methods that handle a set of related events. For example, a MouseListener provides methods for handling MousePressed, MouseReleased, MouseClicked, MouseEnter, and MouseExit events.

As noted earlier, Swing components provide their own listeners to handle mouse and keyboard events. However, Swing components themselves fire events for which your application will need to define listeners. For example, a JRadioButton fires an ActionEvent when its radio button is pushed and your program needs to define an ActionListener in order to handle this event and respond appropriately. The events fired by Swing components are called high-level events because they convey semantic information such as a button push or a menu selection, whereas events fired by the mouse and keyboard are called low-level events because they must be interpreted by an object in order to determine their semantic meaning.