Page

663
23
Introducing the AWT:
Working with Windows,
Graphics, and Text
The Abstract Window Toolkit (AWT) was introduced in Chapter 21, where it was used in
several example applets. This chapter begins its in-depth examination. The AWT contains
numerous classes and methods that allow you to create and manage windows. It is also
the foundation upon which Swing is built. The AWT is quite large and a full description would
easily fill an entire book. Therefore, it is not possible to describe in detail every AWT class,
method, or instance variable. However, this and the following two chapters explain the basic
techniques needed to use the AWT effectively when creating your own applets or stand-alone
GUI-based applications. From there, you will be able to explore other parts of the AWT on your
own. You will also be ready to move on to Swing.
In this chapter, you will learn how to create and manage windows, manage fonts, output
text, and utilize graphics. Chapter 24 describes the various controls, such as scroll bars and
push buttons, supported by the AWT. It also explains further aspects of Java’s event handling
mechanism. Chapter 25 examines the AWT’s imaging subsystem and animation.
Although a common use of the AWT is in applets, it is also used to create stand-alone
windows that run in a GUI environment, such as Windows. For the sake of convenience,
most of the examples in this chapter are contained in applets. To run them, you need to use
an applet viewer or a Java-compatible web browser. A few examples will demonstrate the
creation of stand-alone, windowed programs.
One other point before beginning. Today, most Java programs employ user interfaces
based on Swing. Because Swing provides richer implementations than does the AWT of
some common GUI controls, such as buttons, lists, and check boxes, it is easy to jump to
the conclusion that the AWT is no longer important, that it has been superseded by Swing.
This assumption is, however, quite wrong. As mentioned, Swing is built on top of the AWT.
Thus, many aspects of the AWT are also aspects of Swing. Furthermore, many AWT classes
are used either directly or indirectly by Swing. Finally, for some types of small programs
(especially small applets) that make only minimal use of a GUI, using the AWT rather than
Swing still makes sense. Therefore, even though most interfaces today will be based on
Swing, a solid knowledge of the AWT is still required. Simply put, you can’t be a great Java
programmer without knowing the AWT.

 

Although the basic structure of the AWT has been the same since Java 1.0, some of the
original methods were deprecated and replaced by new ones. For backward-compatibility,
Java still supports all the original 1.0 methods. However, because these methods are not for
use with new code, this book does not describe them.
Window Fundamentals
The AWT defines windows according to a class hierarchy that adds functionality and
specificity with each level. The two most common windows are those derived from
Panel, which is used by applets, and those derived from Frame, which creates a standard
application window. Much of the functionality of these windows is derived from their
parent classes. Thus, a description of the class hierarchies relating to these two classes is
fundamental to their understanding. Figure 23-1 shows the class hierarchy for Panel and
Frame. Let’s look at each of these classes now.
Component
At the top of the AWT hierarchy is the Component class. Component is an abstract class that
encapsulates all of the attributes of a visual component. All user interface elements that are
displayed on the screen and that interact with the user are subclasses of Component. It defines
over a hundred public methods that are responsible for managing events, such as mouse and
keyboard input, positioning and sizing the window, and repainting. (You already used many
of these methods when you created applets in Chapters 21 and 22.) A Component object is
responsible for remembering the current foreground and background colors and the currently
selected text font.
Container
The Container class is a subclass of Component. It has additional methods that allow other
Component objects to be nested within it. Other Container objects can be stored inside of a
Container (since they are themselves instances of Component). This makes for a multileveled
containment system. A container is responsible for laying out (that is, positioning) any
666 P a r t I I : T h e J a v a L i b r a r y
FIGURE 23-1 The class hierarchy for Panel and Frame

 
Introducing Swing
In Part II, you saw how to build user interfaces with the AWT classes. Although the AWT
is still a crucial part of Java, its component set is no longer widely used to create graphic
user interfaces. Today, most programmers use Swing for this purpose. Swing is a set of
classes that provides more powerful and flexible GUI components than does the AWT. Simply
put, Swing provides the look and feel of the modern Java GUI.
Coverage of Swing is divided between two chapters. This chapter introduces Swing.
It begins by describing Swing’s core concepts. It then shows the general form of a Swing
program, including both applications and applets. It concludes by explaining how painting
is accomplished in Swing. The following chapter presents several commonly used Swing
components. It is important to understand that the number of classes and interfaces in the
Swing packages is quite large, and they can’t all be covered in this book. (In fact, full
coverage of Swing requires an entire book of its own.) However, these two chapters will
give you a basic understanding of this important topic.
NOTE For a comprehensive introduction to Swing, see my book Swing: ABeginner’s Guide
published by McGraw-Hill/Osborne (2007).
The Origins of Swing
Swing did not exist in the early days of Java. Rather, it was a response to deficiencies present
in Java’s original GUI subsystem: the Abstract Window Toolkit. The AWT defines a basic set
of controls, windows, and dialog boxes that support a usable, but limited graphical interface.
One reason for the limited nature of the AWT is that it translates its various visual components
into their corresponding, platform-specific equivalents, or peers. This means that the look
and feel of a component is defined by the platform, not by Java. Because the AWT components
use native code resources, they are referred to as heavyweight.
The use of native peers led to several problems. First, because of variations between
operating systems, a component might look, or even act, differently on different platforms.
This potential variability threatened the overarching philosophy of Java: write once, run
anywhere. Second, the look and feel of each component was fixed (because it is defined by
the platform) and could not be (easily) changed. Third, the use of heavyweight components
caused some frustrating restrictions. For example, a heavyweight component is always
rectangular and opaque.
859

C h a p t e r 2 3 : I n t r o d u c i n g t h e A W T : Wo r k i n g w i t h W i n d o w s , G r a p h i c s , a n d T e x t 667
components that it contains. It does this through the use of various layout managers, which
you will learn about in Chapter 24.
Panel
The Panel class is a concrete subclass of Container. It doesn’t add any new methods; it simply
implements Container. A Panel may be thought of as a recursively nestable, concrete screen
component. Panel is the superclass for Applet. When screen output is directed to an applet,
it is drawn on the surface of a Panel object. In essence, a Panel is a window that does not
contain a title bar, menu bar, or border. This is why you don’t see these items when an applet
is run inside a browser. When you run an applet using an applet viewer, the applet viewer
provides the title and border.
Other components can be added to a Panel object by its add( ) method (inherited from
Container). Once these components have been added, you can position and resize them
manually using the setLocation( ), setSize( ), setPreferredSize( ), or setBounds( ) methods
defined by Component.
Window
TheWindow class creates a top-level window. Atop-level window is not contained within any
other object; it sits directly on the desktop. Generally, you won’t create Window objects
directly. Instead, you will use a subclass of Window called Frame, described next.
Frame
Frame encapsulates what is commonly thought of as a “window.” It is a subclass ofWindow
and has a title bar, menu bar, borders, and resizing corners. If you create a Frame object from
within an applet, it will contain a warning message, such as “Java Applet Window,” to the
user that an applet window has been created. This message warns users that the window
they see was started by an applet and not by software running on their computer. (An applet
that could masquerade as a host-based application could be used to obtain passwords and
other sensitive information without the user’s knowledge.) When a Frame window is created
by a stand-alone application rather than an applet, a normal window is created.
Canvas
Although it is not part of the hierarchy for applet or frame windows, there is one other type
of window that you will find valuable: Canvas. Canvas encapsulates a blank window upon
which you can draw. You will see an example of Canvas later in this book.
Working with Frame Windows
After the applet, the type of window you will most often create is derived from Frame. You will
use it to create child windows within applets, and top-level or child windows for stand-alone
applications. As mentioned, it creates a standard-style window.
Here are two of Frame’s constructors:
Frame( )
Frame(String title)
The first form creates a standard window that does not contain a title. The second form creates
a window with the title specified by title. Notice that you cannot specify the dimensions of
the window. Instead, you must set the size of the window after it has been created.

S o f t w a r e D e v e l o p m e n t U s i n g J a v a
Not long after Java’s original release, it became apparent that the limitations and
restrictions present in the AWT were sufficiently serious that a better approach was needed.
The solution was Swing. Introduced in 1997, Swing was included as part of the Java
Foundation Classes (JFC). Swing was initially available for use with Java 1.1 as a separate
library. However, beginning with Java 1.2, Swing (and the rest of the JFC) was fully
integrated into Java.
Swing Is Built on the AWT
Before moving on, it is necessary to make one important point: although Swing eliminates
a number of the limitations inherent in the AWT, Swing does not replace it. Instead, Swing
is built on the foundation of the AWT. This is why the AWT is still a crucial part of Java.
Swing also uses the same event handling mechanism as the AWT. Therefore, a basic
understanding of the AWT and of event handling is required to use Swing. (The AWT
is covered in Chapters 23 and 24. Event handling is described in Chapter 22.)
Two Key Swing Features
As just explained, Swing was created to address the limitations present in the AWT. It does
this through two key features: lightweight components and a pluggable look and feel.
Together they provide an elegant, yet easy-to-use solution to the problems of the AWT.
More than anything else, it is these two features that define the essence of Swing. Each
is examined here.
Swing Components Are Lightweight
With very few exceptions, Swing components are lightweight. This means that they are written
entirely in Java and do not map directly to platform-specific peers. Because lightweight
components are rendered using graphics primitives, they can be transparent, which enables
nonrectangular shapes. Thus, lightweight components are more efficient and more flexible.
Furthermore, because lightweight components do not translate into native peers, the look and
feel of each component is determined by Swing, not by the underlying operating system. This
means that each component will work in a consistent manner across all platforms.
Swing Supports a Pluggable Look and Feel
Swing supports a pluggable look and feel (PLAF). Because each Swing component is rendered
by Java code rather than by native peers, the look and feel of a component is under the
control of Swing. This fact means that it is possible to separate the look and feel of a
component from the logic of the component, and this is what Swing does. Separating out
the look and feel provides a significant advantage: it becomes possible to change the way
that a component is rendered without affecting any of its other aspects. In other words, it is
possible to “plug in” a new look and feel for any given component without creating any
side effects in the code that uses that component. Moreover, it becomes possible to define
entire sets of look-and-feels that represent different GUI styles. To use a specific style, its
look and feel is simply “plugged in.” Once this is done, all components are automatically
rendered using that style.
Pluggable look-and-feels offer several important advantages. It is possible to define a
look and feel that is consistent across all platforms. Conversely, it is possible to create a look

 

 

C h a p t e r 2 9 : I n t r o d u c i n g S w i n g 861
and feel that acts like a specific platform. For example, if you know that an application will
be running only in a Windows environment, it is possible to specify the Windows look and
feel. It is also possible to design a custom look and feel. Finally, the look and feel can be
changed dynamically at run time.
Java SE 6 provides look-and-feels, such as metal and Motif, that are available to all Swing
users. The metal look and feel is also called the Java look and feel. It is platform-independent and
available in all Java execution environments. It is also the default look and feel. Windows
environments also have access to the Windows and Windows Classic look and feel. This
book uses the default Java look and feel (metal) because it is platform independent.
The MVC Connection
In general, a visual component is a composite of three distinct aspects:
• The way that the component looks when rendered on the screen
• The way that the component reacts to the user
• The state information associated with the component
No matter what architecture is used to implement a component, it must implicitly contain
these three parts. Over the years, one component architecture has proven itself to be
exceptionally effective: Model-View-Controller, or MVC for short.
The MVC architecture is successful because each piece of the design corresponds to an
aspect of a component. In MVC terminology, the model corresponds to the state information
associated with the component. For example, in the case of a check box, the model contains
a field that indicates if the box is checked or unchecked. The view determines how the
component is displayed on the screen, including any aspects of the view that are affected
by the current state of the model. The controller determines how the component reacts to the
user. For example, when the user clicks a check box, the controller reacts by changing the
model to reflect the user’s choice (checked or unchecked). This then results in the view
being updated. By separating a component into a model, a view, and a controller, the
specific implementation of each can be changed without affecting the other two. For instance,
different view implementations can render the same component in different ways without
affecting the model or the controller.
Although the MVC architecture and the principles behind it are conceptually sound,
the high level of separation between the view and the controller is not beneficial for Swing
components. Instead, Swing uses a modified version of MVC that combines the view and
the controller into a single logical entity called the UI delegate. For this reason, Swing’s
approach is called either the Model-Delegate architecture or the Separable Model architecture.
Therefore, although Swing’s component architecture is based on MVC, it does not use a
classical implementation of it.
Swing’s pluggable look and feel is made possible by its Model-Delegate architecture.
Because the view (look) and controller (feel) are separate from the model, the look and feel
can be changed without affecting how the component is used within a program.
Conversely, it is possible to customize the model without affecting the way that the
component appears on the screen or responds to user input.
To support the Model-Delegate architecture, most Swing components contain two objects.
The first represents the model. The second represents the UI delegate. Models are defined

 

 

862 P a r t I I I : S o f t w a r e D e v e l o p m e n t U s i n g J a v a
by interfaces. For example, the model for a button is defined by the ButtonModel interface.
UI delegates are classes that inherit ComponentUI. For example, the UI delegate for a button
is ButtonUI. Normally, your programs will not interact directly with the UI delegate.
Components and Containers
ASwing GUI consists of two key items: components and containers. However, this distinction
is mostly conceptual because all containers are also components. The difference between the
two is found in their intended purpose: As the term is commonly used, a component is an
independent visual control, such as a push button or slider. A container holds a group of
components. Thus, a container is a special type of component that is designed to hold other
components. Furthermore, in order for a component to be displayed, it must be held within
a container. Thus, all Swing GUIs will have at least one container. Because containers are
components, a container can also hold other containers. This enables Swing to define what
is called a containment hierarchy, at the top of which must be a top-level container.
Let’s look a bit more closely at components and containers.
Components
In general, Swing components are derived from the JComponent class. (The only exceptions
to this are the four top-level containers, described in the next section.) JComponent provides
the functionality that is common to all components. For example, JComponent supports the
pluggable look and feel. JComponent inherits the AWT classes Container and Component.
Thus, a Swing component is built on and compatible with an AWT component.
All of Swing’s components are represented by classes defined within the package
javax.swing. The following table shows the class names for Swing components (including
those used as containers).
JApplet JButton JCheckBox JCheckBoxMenuItem
JColorChooser JComboBox JComponent JDesktopPane
JDialog JEditorPane JFileChooser JFormattedTextField
JFrame JInternalFrame JLabel JLayeredPane
JList JMenu JMenuBar JMenuItem
JOptionPane JPanel JPasswordField JPopupMenu
JProgressBar JRadioButton JRadioButtonMenuItem JRootPane
JScrollBar JScrollPane JSeparator JSlider
JSpinner JSplitPane JTabbedPane JTable
JTextArea JTextField JTextPane JTogglebutton
JToolBar JToolTip JTree JViewport
JWindow

Notice that all component classes begin with the letter J. For example, the class for a label
is JLabel; the class for a push button is JButton; and the class for a scroll bar is JScrollBar.
Containers
Swing defines two types of containers. The first are top-level containers: JFrame, JApplet,
JWindow, and JDialog. These containers do not inherit JComponent. They do, however,
inherit the AWT classes Component and Container. Unlike Swing’s other components,
which are lightweight, the top-level containers are heavyweight. This makes the top-level
containers a special case in the Swing component library.
As the name implies, a top-level container must be at the top of a containment hierarchy.
Atop-level container is not contained within any other container. Furthermore, every
containment hierarchy must begin with a top-level container. The one most commonly used
for applications is JFrame. The one used for applets is JApplet.
The second type of containers supported by Swing are lightweight containers. Lightweight
containers do inherit JComponent. An example of a lightweight container is JPanel, which
is a general-purpose container. Lightweight containers are often used to organize and
manage groups of related components because a lightweight container can be contained
within another container. Thus, you can use lightweight containers such as JPanel to create
subgroups of related controls that are contained within an outer container.
The Top-Level Container Panes
Each top-level container defines a set of panes. At the top of the hierarchy is an instance of
JRootPane. JRootPane is a lightweight container whose purpose is to manage the other
panes. It also helps manage the optional menu bar. The panes that comprise the root pane
are called the glass pane, the content pane, and the layered pane.
The glass pane is the top-level pane. It sits above and completely covers all other panes.
By default, it is a transparent instance of JPanel. The glass pane enables you to manage
mouse events that affect the entire container (rather than an individual control) or to paint
over any other component, for example. In most cases, you won’t need to use the glass pane
directly, but it is there if you need it.
The layered pane is an instance of JLayeredPane. The layered pane allows components
to be given a depth value. This value determines which component overlays another. (Thus,
the layered pane lets you specify a Z-order for a component, although this is not something
that you will usually need to do.) The layered pane holds the content pane and the (optional)
menu bar.
Although the glass pane and the layered panes are integral to the operation of a top-level
container and serve important purposes, much of what they provide occurs behind the
scene. The pane with which your application will interact the most is the content pane,
because this is the pane to which you will add visual components. In other words, when
you add a component, such as a button, to a top-level container, you will add it to the
content pane. By default, the content pane is an opaque instance of JPanel.
The Swing Packages
Swing is a very large subsystem and makes use of many packages. These are the packages
used by Swing that are defined by Java SE 6.
C h a p t e r 2 9 : I n t r o d u c i n g S w i n g 863

 

864 P a r t I I I : S o f t w a r e D e v e l o p m e n t U s i n g J a v a
javax.swing javax.swing.border javax.swing.colorchooser
javax.swing.event javax.swing.filechooser javax.swing.plaf
javax.swing.plaf.basic javax.swing.plaf.metal javax.swing.plaf.multi
javax.swing.plaf.synth javax.swing.table javax.swing.text
javax.swing.text.html javax.swing.text.html.parser javax.swing.text.rtf
javax.swing.tree javax.swing.undo
The main package is javax.swing. This package must be imported into any program
that uses Swing. It contains the classes that implement the basic Swing components, such as
push buttons, labels, and check boxes.
A Simple Swing Application
Swing programs differ from both the console-based programs and the AWT-based programs
shown earlier in this book. For example, they use a different set of components and a
different container hierarchy than does the AWT. Swing programs also have special
requirements that relate to threading. The best way to understand the structure of a Swing
program is to work through an example. There are two types of Java programs in which
Swing is typically used. The first is a desktop application. The second is the applet. This
section shows how to create a Swing application. The creation of a Swing applet is described
later in this chapter.
Although quite short, the following program shows one way to write a Swing application.
In the process, it demonstrates several key features of Swing. It uses two Swing components:
JFrame and JLabel. JFrame is the top-level container that is commonly used for Swing
applications. JLabel is the Swing component that creates a label, which is a component that
displays information. The label is Swing’s simplest component because it is passive. That is,
a label does not respond to user input. It just displays output. The program uses a JFrame
container to hold an instance of a JLabel. The label displays a short text message.
// A simple Swing application.
import javax.swing.*;
class SwingDemo {
SwingDemo() {
// Create a new JFrame container.
JFrame jfrm = new JFrame(“A Simple Swing Application”);
// Give the frame an initial size.
jfrm.setSize(275, 100);
// Terminate the program when the user closes the application.
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create a text-based label.