By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole
Price: $59.99 USD
£42.50 GBP
Cover | Table of Contents | Colophon
http://java.sun.com/ ),
you'll find Swing described as a set of customizable
graphical components whose look-and-feel (L&F) can be dictated at
runtime. In reality, however, Swing is much more than this. Swing is
the next-generation GUI toolkit that Sun Microsystems created to
enable enterprise development in Java. By enterprise
development
, we mean that programmers can use
Swing to create large-scale Java applications with a wide array of
powerful components. In addition, you can easily extend or modify
these components to control their appearance and behavior.
http://java.sun.com/ ),
you'll find Swing described as a set of customizable
graphical components whose look-and-feel (L&F) can be dictated at
runtime. In reality, however, Swing is much more than this. Swing is
the next-generation GUI toolkit that Sun Microsystems created to
enable enterprise development in Java. By enterprise
development
, we mean that programmers can use
Swing to create large-scale Java applications with a wide array of
powerful components. In addition, you can easily extend or modify
these components to control their appearance and behavior.
javax.accessibility
javax.swing
javax.swing.border
javax.swing.colorchooser
JColorChooser component,
discussed in Chapter 12.
javax.swing.event
% java -jar SwingSet2.jar
color is accessed by the
getColor( ) (to find out the color) and
setColor( ) (to change the color) methods. If a
property has a boolean value, the
get method is often replaced by an is
method; for example, the visible property would
have the isVisible( ) and setVisible( ) methods.
PropertyChangeEvent), when it
was introduced (1.2 is the default; 1.3 and 1.4 are marked where
appropriate), and the property's default value. This
approach certainly saves paper (you didn't really
want a 2,000-page book, did you?) and should make it easier to
understand what a component does and how it is structured.
Furthermore, if you're not already in the habit of
thinking in terms of the JavaBeans architecture, you should get in
the habit. It's a very powerful tool for
understanding component design.
JButton, JTextField, and
JList can be used with the same arguments and
generate the same events as Button,
TextField, and List. Some Swing
containers, like JFrame, take a bit of extra work,
but not much.
JButton, JTextField, and
JList can be used with the same arguments and
generate the same events as Button,
TextField, and List. Some Swing
containers, like JFrame, take a bit of extra work,
but not much.
JButton class
provides a standard way to add image buttons?
// ToolbarFrame1.java
// A simple frame containing a "toolbar" made up of several java.awt.Button
// objects. We'll be converting the Buttons to JButtons in the ToolbarFrame2.java
// file.
//
import java.awt.*;
import java.awt.event.*;
public class ToolbarFrame1 extends Frame {
Button cutButton, copyButton, pasteButton;
public ToolbarFrame1( ) {
super("Toolbar Example (AWT)");
setSize(450, 250);
addWindowListener(new WindowAdapter( ) {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
ActionListener printListener = new ActionListener( ) {
public void actionPerformed(ActionEvent ae) {
System.out.println(ae.getActionCommand( ));
}
};
Panel toolbar = new Panel( );
toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));
cutButton = new Button("Cut");
cutButton.addActionListener(printListener);
toolbar.add(cutButton);
copyButton = new Button("Copy");
copyButton.addActionListener(printListener);
toolbar.add(copyButton);
pasteButton = new Button("Paste");
pasteButton.addActionListener(printListener);
toolbar.add(pasteButton);
// The "preferred" BorderLayout add call
add(toolbar, BorderLayout.NORTH);
}
public static void main(String args[]) {
ToolbarFrame1 tf1 = new ToolbarFrame1( );
tf1.setVisible(true);
}
}
CLASSPATH
so that the Swing components are available during compilation and at
runtime.
import javax.swing.*;
Button objects with JButton
objects. We'll also set up the application to take
advantage of Swing's L&F capabilities;
we've put another row of buttons at the bottom of
the frame that let you select one of the standard L&Fs:
// ToolbarFrame2.java
// The Swing-ified button example
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ToolbarFrame2 extends Frame {
// This time, let's use JButtons!
JButton cutButton, copyButton, pasteButton;
JButton javaButton, macButton, motifButton, winButton;
public ToolbarFrame2( ) {
super("Toolbar Example (Swing)");
setSize(450, 250);
addWindowListener(new WindowAdapter( ) {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
ActionListener printListener = new ActionListener( ) {
public void actionPerformed(ActionEvent ae) {
System.out.println(ae.getActionCommand( ));
}
};
// JPanel works similarly to Panel, so we'll use it.
JPanel toolbar = new JPanel( );
toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));
cutButton = new JButton("Cut");
cutButton.addActionListener(printListener);
toolbar.add(cutButton);
copyButton = new JButton("Copy");
copyButton.addActionListener(printListener);
toolbar.add(copyButton);
pasteButton = new JButton("Paste");
pasteButton.addActionListener(printListener);
toolbar.add(pasteButton);
add(toolbar, BorderLayout.NORTH);
// Add the L&F controls.
JPanel lnfPanel = new JPanel( );
LnFListener lnfListener = new LnFListener(this);
macButton = new JButton("Mac");
macButton.addActionListener(lnfListener);
lnfPanel.add(macButton);
javaButton = new JButton("Metal");
javaButton.addActionListener(lnfListener);
lnfPanel.add(javaButton);
motifButton = new JButton("Motif");
motifButton.addActionListener(lnfListener);
lnfPanel.add(motifButton);
winButton = new JButton("Windows");
winButton.addActionListener(lnfListener);
lnfPanel.add(winButton);
add(lnfPanel, BorderLayout.SOUTH);
}
public static void main(String args[]) {
ToolbarFrame2 tf2 = new ToolbarFrame2( );
tf2.setVisible(true);
}
}JInternalFrame
, which allows you to create free-standing
frames with menus, title bars, and everything else a
Frame needs right inside your application.
Frame object, but
confined to the visible area of the container it is placed in
JDesktopPane
class for this purpose.
You'll see the details of the
JDesktopPane in Chapter 9, but
for now, here's how to get one started:
// Set up the layered pane. JDesktopPane desktop = new JDesktopPane( ); add(desktop, BorderLayout.CENTER);
JInternalFrame constructor takes five
arguments that tailor the look and functionality of the frame:
JTextArea object for you to edit. You can modify
the text and save the file using the File menu in the page frame.
Action objects by
looking at the selected text and insertion point of the active frame.
(We alluded to the Action class after our last
Toolbar example. We'll demonstrate it here and
discuss it thoroughly at the start of the next chapter.) If the
active frame is a site frame, nothing happens.
Action, GraphicsContext,
ChangeEvent, and
PropertyChangeEvent, as well as the
HeadlessException exception. We spend the
remainder of the chapter introducing the JComponent
class, the heart and soul of all Swing components.
JMenu, JPopupMenu, and
JToolBar, can each accept action objects with
their add( ) methods. When an action is added,
these containers automatically create a GUI component, which the
add( ) method then returns to you for customization. For
example, a JMenu or a
JPopupMenu creates and returns a
JMenuItem from an Action while
a JToolBar creates and returns a
JButton. The action is then paired with the newly
created GUI component in two ways: the GUI component registers as a
PropertyChangeListener
for any property changes that might
occur in the action object, while the action object registers as an
JMenu, JPopupMenu, and
JToolBar, can each accept action objects with
their add( ) methods. When an action is added,
these containers automatically create a GUI component, which the
add( ) method then returns to you for customization. For
example, a JMenu or a
JPopupMenu creates and returns a
JMenuItem from an Action while
a JToolBar creates and returns a
JButton. The action is then paired with the newly
created GUI component in two ways: the GUI component registers as a
PropertyChangeListener
for any property changes that might
occur in the action object, while the action object registers as an
ActionListener
on the GUI component. Figure 3-1 shows the interactions between a menu item or
toolbar and an Action.
JButton
generates an ActionEvent (which is really just a
converted mouse event). The ActionEvent class
bundles up interesting stuff like which button the event came from,
when the button was pressed, whether any modifier keys (such as Shift
or Ctrl) were pressed at the time of the event, and so on.
JTextField, JButton, and
JTable, we show the events that they fire and the
methods you use to attach listeners and catch the events.
EEL class implements every listener interface from
the java.awt.event and
javax.swing.event packages. It has a variety of
logging mechanisms to show you the events coming from your
components. You attach an EEL instance to a component (or to multiple
components) using the component's
add . . . Listener( )
method(s). You can choose to have the events sent to a file, to your
console, or to an onscreen text area.
http://www.oreilly.com/catalog/jswing2GraphicsEnvironment
,
GraphicsDevice
, and
GraphicsConfiguration
classes from the
java.awt package. While they
aren't part of Swing proper, these classes are
definitely useful for Swing applications, especially those that take
full advantage of their environment.
GraphicsEnvironment object that describes the
devices on the system with an array of
GraphicsDevice objects. Each
GraphicsDevice contains (or at least may contain)
multiple configurations of device capabilities (such as pixel formats
or which visual screen you're on) bundled up in an
array of GraphicsConfiguration objects.
GraphicsConfiguration class should not be
confused with the DisplayMode class (although
it's easy to do so). The display mode is something
with which most savvy computer users will be familiar. On a system
that supports multisync monitors, the DisplayMode
class encapsulates the width, height, color-depth, and refresh rate
information for a given mode. The
GraphicsConfiguration class stores things like
square versus rectangular pixels.
GraphicsConfiguration could even be used for
devices such as printers. The configuration information is highly
dependent on the native platform and thus varies widely from system
to system. In any given system, both configurations and modes can be
found through the available GraphicsDevice
objects.
JFrame using that configuration.
// GuiScreens.java
//
import java.awt.*;
import javax.swing.*;
public class GuiScreens {
public static void main(String[] args) {
Rectangle virtualBounds = new Rectangle( );
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment( );
GraphicsDevice[] gs = ge.getScreenDevices( );
JFrame frame[][] = new JFrame[gs.length][];
for (int j = 0; j < gs.length; j++) {
GraphicsDevice gd = gs[j];
System.out.println("Device " + j + ": " + gd);
GraphicsConfiguration[] gc = gd.getConfigurations( );
frame[j] = new JFrame[gc.length];
for (int i=0; i < gc.length; i++) {
System.out.println(" Configuration " + i + ": " + gc[i]);
System.out.println(" Bounds: " + gc[i].getBounds( ));
virtualBounds = virtualBounds.union(gc[i].getBounds( ));
frame[j][i] = new JFrame("Config: " + i, gc[i]);
frame[j][i].setBounds(50, 50, 400, 100);
frame[j][i].setLocation(
(int)gc[i].getBounds( ).getX( ) + 50,
(int)gc[i].getBounds( ).getY( ) + 50);
frame[j][i].getContentPane( ).add(new JTextArea("Config:\n" + gc[i]));
frame[j][i].setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
frame[j][i].setVisible(true);
}
System.out.println("Overall bounds: " + virtualBounds);
}
}
}java.beans.PropertyChangeEvent
class. This class passes a reference to
the object, sending the change notification as well as the property
name, its old value, and its new value. The second, javax.
swing.event.ChangeEvent
, is a lighter version that passes only a
reference to the sending object—in other words, the name of the
property that changed, as well as the old and new values, are
omitted.
ChangeEvent class is not part of the
JavaBeans specifications, properties that use this event are not
"bound" according to the JavaBeans
standard. In order to prevent confusion, properties that use a
ChangeEvent to notify listeners of property
changes have not been marked as bound in our property tables.
ChangeEvent includes only a reference
to the event originator, which never changes, you can always define a
single ChangeEvent and reuse it over and over when
firing events from your component.
ChangeEvent
is a stripped-down version of the
java.beans.PropertyChangeEvent class. This class
has no methods or properties, only a constructor. This simplicity
makes it a popular class for developers wanting to fire off their own
events. Recipients get a reference to the source of the event but
then must query the source directly to find out what just happened.
It's great for quick notifications or instances in
which the state of the source component is so complex
it's hard to predict which pieces of information the
recipient will need, but it shouldn't be used simply
to save the component author a little time at the expense of runtime
inefficiency if the recipient always needs to look up information
that could have been part of a
PropertyChangeEvent.
JComponent
is an abstract class that almost all
Swing components extend; it provides much of the underlying
functionality common throughout the Swing component library. Just as
the java.awt.Component class serves as the guiding
framework for most of the AWT components, the
javax.swing.JComponent class serves an identical
role for the Swing components. We should note that the
JComponent class extends
java.awt.Container (which in turn extends
java.awt.Component), so it is accurate to say that
Swing components carry with them a great deal of
AWT
functionality as well.
JComponent extends
Container, many Swing components can serve as
containers for other AWT and Swing components. These components may
be added using the traditional add( ) method of
Container. In addition, they can be positioned
with any Java layout manager while inside the container. The
terminology remains the same as well: components that are added to a
container are said to be its children; the
container is the
parent
of those components. Following the
analogy, any component that is higher in the tree is said to be its
ancestor
, while any component that is lower
is said to be its descendant.
Graphics
object, which not only decreases the amount of memory each component
uses but allows components to have transparent portions and take on
nonrectangular shapes. And, of course, lightweight components are
free of a dedicated L&F.
InputMap
maps
keystrokes to logical
action names. When the user types a key combination,
it's looked up in the input map of the focused
component (and perhaps other components in the active window, as
described earlier). If a match is found, the resulting object is used
as a key in the corresponding component's
ActionMap to look up the concrete
Action class to be invoked. The platform-specific
L&F implementations provide InputMaps
consistent with the key-binding conventions for their platforms.
InputMap, a
java.awt.KeyStroke is always used as the key.
KeyStroke is a simple, immutable class that
represents a particular keyboard action (including any modifier
keys). KeyStrokes are intended to be unique (that
is, if two KeyStroke variables represent the same
action, they should reference the same KeyStroke
instance). To ensure uniqueness, you can't create
KeyStrokes directly; you must obtain them through
the static getKeyStroke( ) factory methods in the
KeyStroke class.
KeyStroke in
an InputMap is an arbitrary object, and any object
can be used as a key for looking up an action in an
ActionMap, in practice the values are
Strings. By convention, their content is a
descriptive name for the action to be performed (such as
copy, print,
save, or the like). This allows
InputMaps to be largely self-documenting
(it's easy to print their contents as a
"cheat sheet" showing the keys that
invoke particular commands) and also improves the readability of code
that requests actions programmatically. The most common way this
string is obtained is by calling getName( ) on the
Action to be added to the map.
InputMaps can be chained together so that common
functionality can be shared in a basic InputMap;
specialized components can add custom keystrokes to their own
JLabel class. In addition,
we'll look at Swing's
Icon interface and an implementation of this
interface called ImageIcon. With just these few
constructs, you'll begin to see how Swing aids in
the sophisticated UI development in Java.
JLabel class.
JLabel class
allows you to add basic, noninteractive labels to a user interface.
Because of its inherent simplicity, there is no model class for
JLabel. Figure 4-1 shows a class
diagram for JLabel. We'll get
into the two relationships to Icon a little later.
JLabel objects may consist of both text and
graphics (icons), but for simple text-only labels, the interface with
JLabel is very similar to that of
java.awt.Label. The code to create and display a
very simple text label looks like this:
// SimpleJLabelExample.java
//
import javax.swing.*;
public class SimpleJLabelExample {
public static void main(String[] args) {
JLabel label = new JLabel("A Very Simple Text Label");
JFrame frame = new JFrame( );
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane( ).add(label); // Adds to CENTER
frame.pack( );
frame.setVisible(true);
}
}
JLabel class contains the properties shown in
Table 4-1. The
icon
and disabledIcon
properties specify the icon to be displayed by default and when the
label is disabled, respectively. If an JLabel class.
JLabel class
allows you to add basic, noninteractive labels to a user interface.
Because of its inherent simplicity, there is no model class for
JLabel. Figure 4-1 shows a class
diagram for JLabel. We'll get
into the two relationships to Icon a little later.
JLabel objects may consist of both text and
graphics (icons), but for simple text-only labels, the interface with
JLabel is very similar to that of
java.awt.Label. The code to create and display a
very simple text label looks like this:
// SimpleJLabelExample.java
//
import javax.swing.*;
public class SimpleJLabelExample {
public static void main(String[] args) {
JLabel label = new JLabel("A Very Simple Text Label");
JFrame frame = new JFrame( );
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane( ).add(label); // Adds to CENTER
frame.pack( );
frame.setVisible(true);
}
}
JLabel class contains the properties shown in
Table 4-1. The
icon
and disabledIcon
properties specify the icon to be displayed by default and when the
label is disabled, respectively. If an icon is
specified without a disabledIcon, a
disabledIcon is automatically created by
converting the default icon to grayscale. The
font
property is shown in this table only because the setFont( ) method is overridden to call repaint( ) after calling super.setFont( )