AWT Components

This section provides a brief overview of many of the components Swing provides, showing examples of each one and a short description of how it's used. Most of the components are simple and intuitive to use, although a few are more complex. For more detailed information on a given component you may find it useful to review the information in Oracle's Swing tutorial, which includes individual sections on each of the different types of components.

Let's begin by looking at the inheritance hierarchy of a Swing class we've already encountered, specifically JFrame.

java.lang.Object | +--java.awt.Component | +--java.awt.Container | +--java.awt.Window | +--java.awt.Frame | +--javax.swing.JFrame
Figure 1: Type hierarchy of the JFrame class.

Notice that none of the other types in JFrame's inheritance hierarchy are defined in the javax.swing package; instead all of them are Abstract Windowing Toolkit (AWT) classes defined in the java.awt package. This illustrates a point made in another tutorial that's worth repeating: Swing depends both directly and indirectly on many AWT classes, and we'll now briefly look at the ones in this hierarchy.

Component

As mentioned before, Component is the base class from which all visual AWT and Swing types inherit, though as the above hierarchy shows, most don't extend it directly. Component includes a large number of methods that are common to most or all AWT and Swing components, such as the ones used in an earlier section to set the size and visibility properties of a JFrame. Besides those properties, Component defines a location that's defined by integer (int) X and Y coordinates, foreground and background colors used when drawing (also called "rendering") the component, and many others.

Container

The next entry in the inheritance hierarchy is Container, and although it doesn't define nearly as many methods as Component it's still a very important class to understand. The API documentation for Container describes it as, "a component that can contain other components", which may not be a very helpful explanation if you're not already familiar with what it does.

Essentially a container maintains a collection that can hold references to other components that it "contains", and when the container itself is visible on the screen those components that it contains will appear on top of / inside the container itself. The components it contains are referred to as the container's child components and the container is said to be the parent container of those children.

A parent can obviously have multiple children, but a component can only have (at most) a single parent. If you add a component to one container and then add it to a second one, it will automatically be removed from the first container's collection of children.
Children are added to a container by calling the container's add() method, passing a reference to a component that should be made a child of the container, and a child added to a container will remain the container's child until the child is explicitly removed or is added to a different container. You can retrieve the list of child components for a container by calling its getComponents() method, which returns the container's children as an array of Component instances.

To better understand the importance of containers, let's look at a slightly more complex user implementation of JFrame, specifically a dialog that prompts the user to enter logon credentials. The example in Figure 1 shows a JFrame like the one created in another section of this tutorial, but with an important difference: instead of just an empty frame, we have a frame that contains several different types of components, namely labels, text fields, and buttons.

Simple Logon Dialog
Figure 1: A simple logon dialog.
Returning to our discussion of containers, you may have guessed that the way to construct a user interface component like this dialog is by using adding child components -- namely things like labels, text fields, and buttons -- to a parent container such as a frame. And in fact, that's exactly how it's done, specifically using the previously mentioned add() method.

It's important to note at this point that a container is both a container and a component, since Container extends the Component class. What this means is that a container can have children that are themselves containers, and those children can themselves hold other children, etc. In fact, for a Swing application, there are always multiple such levels within the containment hierarchy because some components --including JFrame -- automatically add child components that you normally won't see or need to know or care about. Those automatically created child components are used to support some of the more advanced features of Swing, such as the ability to display popup menus, and in most cases they're both literally and figuratively transparent to you.

To illustrate this point, let's create a JFrame and pass it to a method that recursively traverses the component hierarchy and displays the subcomponents of each container:

import java.awt.Component; import java.awt.Container; import javax.swing.JFrame; public class ShowHierarchy { public static void main(String[] args) { displayHierarchy(new JFrame(), ""); } private static void displayHierarchy(Container container, String prefix) { System.out.println(prefix + container.getClass().getName()); String childPrefix = prefix + " "; Component[] children = container.getComponents(); for (Component child : children) { if (child instanceof Container) { displayHierarchy((Container)child, childPrefix); } else { System.out.println(childPrefix + child.getClass().getName()); } } } }
Listing 1: Code that diplays the component hierarchy for a JFrame.

Running this code produces the following output:

javax.swing.JFrame javax.swing.JRootPane javax.swing.JPanel javax.swing.JLayeredPane javax.swing.JPanel

This illustrates that the JFrame automatically create a JRootPane child component, and the root pane in turn has two child components, a JPanel and JLayeredPane, and finally the layered pane has a single JPanel child.

Window

Notice that when we displayed the containment hierarchy for our frame that the frame itself appeared at the top of the component tree. Although we said earlier that containers can be added to other containers, the JFrame class belongs to a special category of components that can't be added to other containers. The components in that category are collectively known as windows, and each one directly or indirectly extends the Window class. Windows are also sometimes referred to as top-level containers (or sometimes "top-level windows") because they always appear at the top of component hierarchy like the one we generated.

In the section on Swing's architecture we briefly examined the difference between heavyweight and lightweight components. Specifically, a lightweight component exists only as a Java object within the JVM, but a heavyweight component has both a Java object and a corresponding entity (a "peer") that's maintained by the native operating system such as Windows. In fact, it's the heavyweight component you see on the screen, which is why calling dispose() to release the peer resources causes a frame to disappear.

All window objects are heavyweight components: their appearance and behavior is ultimatedly controlled by the native operating system, and the corresponding Java object is just a wrapper that provides access to the window through its peer. And as we saw in another section of the tutorial regarding JFrame, the EDT will remain alive as long as at least one undisposed window exists.

Frame

The Frame is essentially the Abstract Windowing Toolkit (AWT) representation of a frame, and this is the final supertype in the JFrame hierarchy. The API documentation for Frame describes it as having "a title and a border", although what really distinguishes a frame from the other windows is its ability to be minimized and maximized.