Swing Overview

Swing is a framework for building GUI-based applications. Swing provides features not present in the AWT.

AWT components are based on the peer model. Every AWT component has a corresponding peer class written in the native system's code. For example, the java.awt.Button class has a peer named java.awt.peer.Button. The peer class serves as the interface between the Java code and the native windowing system. The methods in the peer class are written in native code. AWT components are considered heavyweight because they depend on the native (peer) system for drawing and rendering. Swing is considered lightweight because most of its components are written in Java and are platform independent.

Swing's top level window classes - JApplet, JDialog, JFrame, and JWindow are defined as extensions to their AWT counterparts. The JComponent class, which is the basis for all Swing components is derived from java.awt.Container. Finally, all GUI applications and applets use layout managers (java.awt.FlowLayout), fonts (java.awt.Font), and colors (java.awt.Color) that are defined in the AWT. Swing is not a replacement for the AWT but rather an extension. All classes directly related to Swing are contained within the javax.swing package. For complete documentation visit the Swing website.

Some of the packages included under Swing are: javax.swing.event, javax.swing.plaf, and javax.swing.text. The term plaf is an acronym for pluggable look and feel. For example the javax.swing.plaf.motif package contains the classes that implement the Motif interface, a common Unix based interface.

Java's Swing components have been implemented using the model-view-controller (MVC) model. Any Swing component can be viewed in terms of three independent aspects: what state it is in (its model), how it looks (its view), and what it does (its controller). Suppose the user clicks on a button. This action is detected by the controller. The controller tells the model to change into the pressed state. The model in turn generates an event that is passed to the view. The event tells the view that the button needs to be redrawnto reflect its change in state.

Event Model

Whenever something happens within a GUI - there is a keystroke or mouse click - an event object is generated. The event object is passed to the event listener that has been registered to handle that component's events.

private JButton button = new JButton ( "ON" );
add ( button );
button.addActionListener ( this );

A listener is any object that implements a listener interface. In order to complete the event handling code, the ActionListener interface has to be implemented. For the ActionListener interface it means that the method actionPerformed() has to be defined. The event model is the same for both AWT and Swing classes. The Swing package introduces many additional events.

In Swing special action objects can be created as an extension of traditional event handling. These action objects can be attached to various components, such as buttons, to represent an action that should be executed when the button is pressed.

Swing Components

All root components - JComponent, JWindow, JFrame, JDialog, and JApplet all use the containment model JRootPane. The JRootPane class provides a content pane, which constitutes the main area of the root component. The pane acts like a traditional container for which a layout manager can be registered and components added. Operations, such as setting a layout manager, and adding and removing components, must be done on the content pane when working with the root components in Swing.
JFrame theFrame = new JFrame ( "New Window" );
Container window = theFrame.getContentPane();
JButton button = new JButton ( "Click Here" );
window.add ( button );
Other Swing containers such as JPanel are not root components and use the traditional containment model.
JPanel panel = new JPanel();
JButton button = new JButton ( "Click Here" );
panel.add ( button );

All lightweight Swing components inherit from the JComponent class. The abstract JComponent class defines common functionality that is shared by all lightweight Swing components. The inheritance hierarchy does not directly mirror the inheritance hierarchy of the AWT components. For example the common functionality of all button like compnents has been factored out into the AbstractButton class. Buttons and labels can have text or image or both.

JPanel clas provides a generic container that uses the traditional containment model, just like Panel in the AWT. A layout manager can be registered with the container, and controls can be added and removed. The frame is a top-level container. It exists to provide a place for other Swing components to paint themselves. The panel is an intermediate container. Its only purpose is to simplify the positioning the GUI controls like button and label. Here is code that adds the button and the label to the panel and the panel to the frame.

JFrame frame = new JFrame ( "A Frame" );
JButton button = new JButton ( "ON" );
JLabel label = new JLabel ( "Quit" );
JPanel pane = new JPanel();
pane.add ( button );
pane.add ( label );
frame.getContentPane().add ( pane, BorderLayout.CENTER );

JMenuBar component can contain JMenu components and presents them as a horizontal bar of pull-down menus.

JToolBar component is usually placed in one of the compass directions of a container using BorderLayout.

BoundedRangeModel - the components JSrollBar, JSlider, and JProgressBar revolve around tracking a value within certain bounds. The bounded range model represents a changeable integer interval within a bounded range. When the user manipulates the slider the model is updated. Each time the values in the model change, a ChangeEvent object is fired off to all the listeners registered with the model object.

BoxLayout Manager

The BoxLayout manager places the components either horizontally in a row or vertically in a column. The row or column does not wrap, regardless of resizing the window. When a box layout manager is created, its major axis is specified in the constructor. Components, when added, are inserted at the end of the row (or bottom of the column).

BoxLayout ( Container target, int axis )

where axis can be X_AXIS or Y_AXIS.

Inner Classes and Adapter Classes

Examine the following piece of code:
window.addWindowListener ( new WindowAdapter()
  {
    public void windowClosing ( WindowEvent evt )
    {
      System.exit ( 0 );
    }
  }
);
This is a listener that listens for window closing events. When such an event occurs, it exits the application by calling System.exit(). The syntax used here is an example of an anonymous inner class. An inner class is a class defined within another class. Anonymous inner classes provide a useful way of creating classes and objects on the fly to handle just this kind of listener task. The syntax used enables us to write one expression that both defines a class and creates an instance of it to listen for window closing events. It is anonymous, meaning we are not giving it a name, so you cannot create other instances of it in the program. Note that the body of the class definition is placed right after the new keyword, which takes the place of the argument to the addWindowListener() method.

An adapter class is a wrapper class that implements trivial versions of the abstract methods that make up a particular interface. The WindowAdapter class implements the methods of the WindowListener interface. However, the WindowListener interface contains seven methods. But we only want to use the windowClosing() method, which is implemented in the anonymous inner class.

The following piece of code illustrates how to to setup a Swing application.

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

public class SwingApplication {
    private static String labelPrefix = "Number of button clicks: ";
    private int numClicks = 0;

    public Component createComponents() {
        final JLabel label = new JLabel(labelPrefix + "0    ");

        JButton button = new JButton("Swing Button");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                numClicks++;
                label.setText(labelPrefix + numClicks);
            }
        });
        label.setLabelFor(button);
        
        JPanel pane = new JPanel();
        pane.setBorder(BorderFactory.createEmptyBorder(
                                        30, //top
                                        30, //left
                                        10, //bottom
                                        30) //right
                                        );
        pane.setLayout(new GridLayout(0, 1));
        pane.add(button);
        pane.add(label);

        return pane;
    }

    public static void main(String[] args) {
        
        //Create the top-level container and add contents to it.
        JFrame frame = new JFrame("SwingApplication");
        SwingApplication app = new SwingApplication();
        Component contents = app.createComponents();
        frame.getContentPane().add(contents, BorderLayout.CENTER);

        //Finish setting up the frame, and show it.
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        frame.pack();
        frame.setVisible(true);
    }
}