Professional Documents
Culture Documents
SL-320 GUI Construction With Java Foundation Classes
SL-320 GUI Construction With Java Foundation Classes
Foundation Classes
SL-320
Student Guide
Enterprise Services
MS BRM01-209
500 Eldorado Blvd.
Broomfield, Colorado 80021
U.S.A.
i
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
Swing Foundations....................................................................................2-1
Relevance............................................................................................ 2-2
Objectives ........................................................................................... 2-3
Comparing Swing and AWT Components ................................... 2-4
Naming and Event Model .......................................................2-4
Selecting Swing or AWT ..........................................................2-5
Converting From AWT to Swing.................................................... 2-6
New Components in Swing............................................................. 2-7
Top-Level Swing Containers ........................................................... 2-8
Using a RootPaneContainer.......................................................... 2-9
Overview ....................................................................................2-9
The Root, Glass, and Layered Panes ....................................2-10
JFrame Essentials............................................................................ 2-11
Background..............................................................................2-11
Reacting to the System Menu................................................2-12
Exercise: Converting an AWT GUI to Swing.............................. 2-13
Preparation...............................................................................2-13
Tasks .........................................................................................2-13
Exercise Summary...................................................................2-14
Check Your Progress ...................................................................... 2-15
Think Beyond .................................................................................. 2-16
Basic Swing Components.........................................................................3-1
Relevance............................................................................................ 3-2
Objectives ........................................................................................... 3-3
Overview ....................................................................................3-4
Creating an Icon.......................................................................3-5
Implementing the Icon Interface ...........................................3-6
The JLabel Class .............................................................................. 3-7
Overview ....................................................................................3-7
JLabel Example........................................................................3-8
Tooltips ............................................................................................... 3-9
Buttons.............................................................................................. 3-10
The JButton Class .......................................................................... 3-11
Overview ..................................................................................3-11
JButton Example....................................................................3-12
The JCheckBox Class...................................................................... 3-14
Overview ..................................................................................3-14
JCheckBox Example ...............................................................3-15
The JRadioButton Class ............................................................... 3-16
Overview ..................................................................................3-16
JRadioButton Example.........................................................3-17
The JComboBox Class...................................................................... 3-19
Overview ..................................................................................3-19
JComboBox Example ...............................................................3-20
The JMenu Class .............................................................................. 3-22
iii
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
Models, Views, and Controllers..............................................................6-1
Relevance............................................................................................ 6-2
Objectives ........................................................................................... 6-3
MVC Overview ................................................................................. 6-4
Benefits of MVC ................................................................................ 6-8
Implementing MVC in JDK 1.1 ..................................................... 6-10
Event Sourcing ................................................................................ 6-12
Handling Listeners ......................................................................... 6-14
Dispatching the Event .................................................................... 6-16
MVC in Swing ................................................................................. 6-18
Exercise: MVC Demonstration Using the 1.1 Event Model ...... 6-20
Preparation...............................................................................6-20
Tasks .........................................................................................6-20
Exercise Summary...................................................................6-22
Check Your Progress ...................................................................... 6-23
Think Beyond .................................................................................. 6-24
Swing MVC Components ........................................................................7-1
Relevance............................................................................................ 7-2
Objectives ........................................................................................... 7-3
MVC In Swing ................................................................................... 7-4
Using a JList.................................................................................... 7-6
Using a ListModel ........................................................................... 7-7
Exercise 1: Sharing a Model With MVC ........................................ 7-9
Preparation.................................................................................7-9
Tasks ...........................................................................................7-9
Exercise Summary...................................................................7-10
Actions, KeyStrokes, and Models ................................................. 7-11
Defining an Action ........................................................................ 7-12
Action and Model Interactions..................................................... 7-14
Exercise 2: Defining Action Classes ............................................ 7-15
Preparation...............................................................................7-15
Tasks .........................................................................................7-15
Exercise Summary...................................................................7-16
Check Your Progress ...................................................................... 7-17
Think Beyond .................................................................................. 7-18
Using the JTable........................................................................................8-1
Relevance............................................................................................ 8-2
Objectives ........................................................................................... 8-3
JTable Fundamentals ...................................................................... 8-4
Essential JTable Support Classes .................................................. 8-6
The TableModel Interface ............................................................... 8-8
The TableColumnModel Interface and TableColumn Class..... 8-10
Using a JTable................................................................................ 8-11
Using an AbstractTableModel................................................... 8-12
Controlling Table Appearance...................................................... 8-14
v
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
Exercise: Using JTextPane and Styles ...................................... 10-14
Preparation.............................................................................10-14
Tasks .......................................................................................10-14
Exercise Summary.................................................................10-16
Check Your Progress .................................................................... 10-17
Think Beyond ................................................................................ 10-18
More Swing Features...............................................................................11-1
Relevance.......................................................................................... 11-2
Objectives ......................................................................................... 11-3
Swing Is Not Thread Safe .............................................................. 11-4
Calling Methods From Other Threads......................................... 11-8
Communicating Between Threads ............................................. 11-10
Swing Component Appearance.................................................. 11-12
Using Borders ................................................................................ 11-13
Border Appearance ....................................................................... 11-14
Controlling Look and Feel ........................................................... 11-15
Focus Handling ............................................................................. 11-18
Controlling Default Focus............................................................ 11-19
Focus Traversal.............................................................................. 11-20
Exercise 1: Observe Default Focus Traversal ............................ 11-22
Tasks .......................................................................................11-22
Exercise 2: Control Focus Traversal ........................................... 11-23
Preparation.............................................................................11-23
Tasks .......................................................................................11-23
Exercise 3: Control Default Focus Position ............................... 11-24
Preparation.............................................................................11-24
Tasks .......................................................................................11-24
Exercise 4: Install a Look and Feel .............................................. 11-25
Preparation.............................................................................11-25
Tasks .......................................................................................11-25
Exercise Summary......................................................................... 11-26
Check Your Progress .................................................................... 11-27
Think Beyond ................................................................................ 11-28
Utility Panes..............................................................................................12-1
Relevance.......................................................................................... 12-2
Objectives ......................................................................................... 12-3
Utility Panes..................................................................................... 12-4
The JFileChooser ......................................................................... 12-5
Description...............................................................................12-5
Example ....................................................................................12-6
Using the JFileChooser.......................................................12-7
The JTabbedPane............................................................................ 12-9
Description...............................................................................12-9
Using the JTabbedPane .......................................................12-10
JTabbedPane Example.........................................................12-12
vii
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
Component Requirements............................................................. 14-4
Creating a New Component.......................................................... 14-5
Lightweight Components .............................................................. 14-7
Event Handling ............................................................................... 14-8
Event Sourcing Choices................................................................ 14-10
Recap.......................................................................................14-11
Add / Remove Listener Methods.......................................14-11
Event Firing Convenience Method.....................................14-11
Creating a New Component........................................................ 14-12
Exercise: Create a New Component........................................... 14-16
Preparation.............................................................................14-16
Tasks .......................................................................................14-16
Exercise Summary.................................................................14-17
Check Your Progress .................................................................... 14-18
Think Beyond ................................................................................ 14-19
GUI Data Transfer ...................................................................................15-1
Relevance.......................................................................................... 15-2
Objectives ......................................................................................... 15-3
Data Types ....................................................................................... 15-4
The System Clipboard .................................................................... 15-6
Paste From Clipboard..................................................................... 15-7
Overview ..................................................................................15-7
Example ....................................................................................15-8
Copy to Clipboard .......................................................................... 15-9
Overview ..................................................................................15-9
Example ..................................................................................15-10
Implementing Transferable..................................................... 15-11
Exercise 1: Implementing Cut-and-Paste .................................. 15-13
Preparation.............................................................................15-13
Tasks .......................................................................................15-13
Exercise Summary.................................................................15-14
Drag-and-Drop.............................................................................. 15-15
Comparison With Cut-and-Paste .......................................15-15
X Windows Mechanisms .....................................................15-16
Drag-and-Drop Actions .......................................................15-16
DropTarget and DropTargetListener ................................... 15-17
Overview ................................................................................15-17
Accepting or Rejecting the Drop.........................................15-18
The drop Method ..................................................................15-18
Example ..................................................................................15-19
DragSource, DragSourceListener, and
DragGestureListener............................................................. 15-21
Overview ................................................................................15-21
Example ..................................................................................15-23
Exercise 2: Implementing Drag-and-Drop ................................ 15-24
ix
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
Adding Fonts .................................................................................... C-4
Font Configuration .......................................................................... C-6
Adding a Font to Microsoft Windows .......................................... C-8
Adding a Font to a Solaris System............................................... C-10
Check Your Progress ..................................................................... C-11
Undo /Redo Handling ..............................................................................D-1
Relevance........................................................................................... D-2
Objectives .......................................................................................... D-3
Undo/Redo Features....................................................................... D-4
Undo Example .................................................................................. D-6
Check Your Progress ....................................................................... D-9
Course Goal
GUI Construction With Java Foundation Classes provides you with the
knowledge and skills necessary to implement top quality user
interfaces for real applications. It covers the features and use of Java
Foundation Classes (JFC) components and the component code-named
Project Swing (Swing components), as well as printing and
localization issues.
xi
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
Course Overview
With the advent of Swing and its maturing into the core packages, Java
technology now has a fully featured universally available graphical
user interface (GUI) library. Additional features of the Java
Development Kit (JDK) core packages provide full support for
localization and internationalization of programs. This is particularly
important in the context of Internet distribution of applets.
Developers taking this class will gain the essential skills to create top
quality user interfaces using the features of core JDK, Abstract
Windowing Toolkit (AWT), JFC, and Swing, as well as skills needed
for printing and localization of a program.
Each module begins with a course map that enables you to see what
you have accomplished and where you are going in reference to the
course goal. A complete map of this course is shown below.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
Module 1 Introduction.
This module shows how to use the new print features of JDK 1.2.
These features allow you greater control over page format,
resolution and support the concept of creating a complete multi-
page document from multiple smaller documents.
Swing takes text editing from the simple concepts of the AWT and
adds the capabilities for multiple font, multiple styled editing.
This module discusses all these features and additionally shows
how to incorporate Components and Images into a document.
Note The course does not discuss the detailed issues of creating a
new look and feel.
The skills for GUI Construction With Java Foundation Classes are shown
in the first column of the matrix below. The black boxes indicate the
main coverage for a topic; the gray boxes indicate the topic is briefly
discussed.
Module
Skills Gained 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Skills Gained 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Describe the strengths of the design
pattern and analyze a suitable given
system problem in terms of MVC
Use the elements of MVC to obtain
maximum flexibility in a Swing
application
Write programs that run
appropriately under different
languages/locales
Apply character encoding
conversion techniques
Use localized resources to present
messages in the users language
Program drag-and-drop and cut-
and-paste operations
The table below provides a rough estimate of pacing for this course.
This course does not cover the topics shown on the above overhead.
Many of the topics listed on the overhead are covered in other courses
offered by Sun Educational Services:
To be sure you are prepared to take this course, can you answer these
questions in the affirmative?
Can you make basic use of the AWT, including laying out GUIs
with flow, grid, and border layout managers; and using simple
components, including programming event responses?
Now that you have been introduced to the course, introduce yourself
to each other and the instructor, addressing the items shown on the
above overhead.
Icons
Additional resources Indicates additional reference materials are
available.
Typographical Conventions
Courier is used to represent parts of a Java programming language
source file, such as class names, methods, and keywords. Methods
generally are not followed by parentheses, unless either a formal or
actual parameter list is shown. So, a reference to the doIt method
may refer to any overloaded method called doIt, without specifying a
particular signature. On the other hand, a reference to the doIt()
method specifically refers to a method called doIt that takes no
arguments.
Courier is also used for the names of command, files, and directories,
as well as on-screen computer output. For example:
Courier bold is used for characters and numbers that you type. For
example:
system% su
Password:
Palatino italics is used for book titles, new words or terms, or words
that are emphasized. For example:
Course Map
This module discusses the relationships among AWT, JFC, Swing, and
competing libraries.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
1-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
1
Relevance
Select appropriate components from the Swing set for any given
user interface (UI) requirement
Introduction 1-3
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
1
Course Contents
This course discusses most of the commonly used features of the Java
Foundation Classes, including the Swing component set. However, it
does not cover the two-dimensional (2D) drawing APIs, nor will you
learn how to create your own look and feel.
In addition to elements of the JFC, you will learn about printing with
the newer mechanisms added at JDK 1.2.
What Is JFC?
Introduction 1-5
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
1
What Is JFC?
What is Swing?
Introduction 1-7
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
1
Printing
The printing features of JDK 1.1 are still available, but have been
augmented by a new set, in the package java.awt.print, that
provides greater control over the output, including permitting higher
resolution printing and supporting the concept of page layouts and
books.
The AWT has been used successfully for a while, including for very
large-scale commercial applications, so why has a new component set
been introduced?
Introduction 1-9
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
1
Why Not Use AWT?
General Features
It is likely that some other GUI component kit will replace the AWT kit
of choice. Think about what features are important to you in a GUI
component kit. JFC/Swing is, after all, not your only option, and you
need to be able to compare different sets before making a final choice.
Features that might be important to you include:
Introduction 1-11
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
1
What Should a Replacement for AWT Offer?
Introduction 1-13
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
1
Performance Features
No program was ever criticized for being too fast, and you must
always bring performance issues into the equation when you make
design decisions. For a Java applet or application, three key factors are
involved in performance, or perceived performance, where GUI
components are concerned. These are:
The library itself should be 100% Pure Java, if you want to have
your application certified as such.
Introduction 1-15
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
1
What Should a Replacement for AWT Offer?
Although JFC and Swing score highly in all the respects that were just
discussed, there are a few considerations to keep in mind when you
approach a project with the JFC/Swing packages.
In JDK 1.1, the JFC/Swing classes are not core to the JDK, and differ
very slightly from the JFC/Swing release that is part of core JDK 1.2. If
you wish to write code that uses Swing and runs under both JDK 1.1
and 1.2, you must write for JDK 1.1, and make the Swing distribution
for 1.1 available on the 1.2 platforms.
Introduction 1-17
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
1
Exercise: Investigate Swing Component set
Preparation
The JDK 1.2 release includes a useful demonstration program that
shows all the Swing components and enables you to experiment with
the look and feel of each of them.
Tasks
Under the main installation directory of your JDK there is a directory
called demo. Under that is a directory called jfc, and under that is a
directory called SwingSet. Make the SwingSet directory your current
directory and issue the command:
java SwingSet
After a moment you will see a loading window with a progress bar.
When the loading process has completed, you will see a window with
a banner on it and a tab selection panel above. Select each of the tabs
and ensure that you have seen all the components in the Swing set.
Experiment with the control options that are offered by most of the
pages. Consider how these components could be applied to your
work.
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Introduction 1-19
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
1
Check Your Progress
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
Select appropriate components from the Swing set for any given
UI requirement
Given that Swing is largely backward compatible with AWT and the
delegation event model, do you think you could write code to use
some of these components already? What changes do you think you
might have to make to an existing AWT 1.1 program to use Swing
components instead?
Introduction 1-21
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
1
Course Map
This module introduces some of the essential aspects of the Swing set
and addresses the first issues that you must understand to succeed in
translating a GUI from the AWT to Swing.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
2-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
2
Relevance
Would you like to see any new components added to the basic AWT
set?
Name the Swing components that are direct substitutes for the
AWT components and modify an AWT user interface to use these
Swing components
Understand the multiple panes of the JFrame, and write code that
correctly uses the content pane for holding other components
You can investigate the full set of Swing components using the
SwingSet demonstration that is provided with the Swing distribution
or with JDK 1.2 distributions.
Using a RootPaneContainer
Overview
A RootPaneContainer is actually a container for a number of other
panes; these are the root, glass, layered, and content panes. Most of the
time, you only need to be concerned with the content pane.
The LayeredPane can contain a menubar, and also holds the all-
important ContentPane.
JFrame Essentials
Background
Much of the time, when you use a RootPaneContainer, it will
actually be a JFrame. This class is the Swing replacement for a
java.awt.Frame, and is similar to that class.
DO_NOTHING_ON_CLOSE
HIDE_ON_CLOSE
DISPOSE_ON_CLOSE
Note If you close the last or only JFrame, and have requested
DISPOSE_ON_CLOSE behavior, the AWT thread does not exit, and
neither does the Java Virtual Machine (JVM).
Preparation
Read the file README in the labs directory for module 2.
Tasks
Edit the files ConvertIF1.java, ConvertIF2.java, and
ConvertIF3.java. Change all the components to their Swing
equivalents and modify the code appropriately to make any other
necessary changes.
If you have difficulty, there are some hints in the file HINTS. Try not to
look at this file too soon.
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
Name the Swing components that are direct substitutes for the
AWT components and modify an AWT user interface to use these
Swing components
Understand the multiple panes of the JFrame, and write code that
correctly uses the content pane for holding other components
Why do you suppose that the Swing top-level containers need a glass
pane to catch events?
Can you guess what consequence might arise if you add an AWT
(non-lightweight) component to a Swing container that has non-Swing
components in a stacking order on the layered pane?
Course Map
This module introduces some fundamental Swing components,
including Icons and Buttons.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
3-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
3
Relevance
Are there any features of Swing that are not present in AWT that you
might want to use?
JLabel
JButton
JCheckBox
JRadioButton
ToolTips
JComboBox
JMenu
Overview
Most Swing components support graphics. You can place images in
buttons, labels, lists, and menus. At the heart of all of the graphics
capabilities in Swing is the Icon interface.
Creating an Icon
The simplest way to create an Icon is to supply an image file to the
constructor of the ImageIcon class. Three constructors provide
different ways of specifying the location of the image file.
Icon icon = new ImageIcon(Image i);
Icon icon = new ImageIcon(String filename);
Icon icon = new ImageIcon(URL url);
These constructors all create an Icon object that can be used with
most of the other Swing components.
Overview
One of the simplest Swing components is the JLabel. This class
contains all of the functionality associated with the AWT Label and
also supports icons.
You can construct a label using only an Icon. This is a convenient way
to put an image into an application.
Additionally, you can specify how the text and the Icon are to align.
The alignment feature uses values defined in the SwingConstants
interface.
JLabel Example
1 import java.awt.*;
2 import javax.swing.*;
3
4 public class IconTest extends JPanel {
5
6 public IconTest() {
7 TargetIcon target = new TargetIcon();
8
9 setLayout(new GridLayout(4, 1));
10 add(new JLabel("This is a normal label"));
11 add(new JLabel("This label has an icon", target,
12 SwingConstants.LEFT));
13 add(new JLabel("The next label has only an icon:"));
14 add(new JLabel(target));
15 }
16
17 public static void main(String args[]) {
18 IconTest it = new IconTest();
19 JFrame jf = new JFrame("Icon on a JLabel");
20 jf.getContentPane().add(it, BorderLayout.CENTER);
21 jf.setVisible(true);
22 }
23 }
This example produces labels showing text and or images. The images
are generated using the TargetIcon class from the previous section.
Tooltips
Buttons
The Swing package provides versions of all the AWT buttons. Like
other Swing components, Swing buttons can display graphics as well
as text.
You create a basic push button in Swing using the JButton class.
Overview
JButton objects can be created with a simple String argument to the
constructor, in which case they display that text as their label, just as
the AWT button did.
Overview (Continued)
If you create a JButton with text, the label text is used by default as
the action command string. However, if you create a graphics-only
button or if the default action command string (which is the text label
of the button) is not what you need, you can define the action
command explicitly using the setActionCommand method.
JButton Example
1 import java.awt.event.*;
2
3 public class CutCopyPaste implements ActionListener {
4
5 public static final String CUT = "CUT";
6 public static final String COPY = "COPY";
7 public static final String PASTE = "PASTE";
8 String testMode;
9
10 public CutCopyPaste(String name) {
11 testMode = name;
12 }
13
14 public void actionPerformed(ActionEvent ae) {
15 if (testMode != null) {
16 if (ae.getActionCommand() == CUT) {
17 System.out.println("Cut from " + testMode);
18 }
19 else if (ae.getActionCommand() == COPY) {
20 System.out.println("Copy from " + testMode);
21 }
22 else if (ae.getActionCommand() == PASTE) {
23 System.out.println("Paste from " + testMode);
24 }
25 }
26 }
27 }
This example demonstrates how the buttons can be created, and how
the action command can be set explicitly, even though the buttons do
not have any text.
Overview
Checkboxes are directly supported by Swing, using the JCheckBox
class. Note that the class name has a capital B in it, which is different
from the corresponding java.awt.Checkbox class.
Like the other Swing components, you can use icons on a JCheckBox.
JCheckBox Example
This code example shows how to use a JCheckBox in its simplest
form:
1 import javax.swing.*;
2 import java.awt.*;
3
4 public class CBox extends JPanel {
5 JCheckBox tb1, tb2, tb3;
6
7 public CBox() {
8 setLayout(new GridLayout(3,1));
9 add(tb1 = new JCheckBox("Left Channel"));
10 add(tb2 = new JCheckBox("Right Channel"));
11 add(tb3 = new JCheckBox("Bass Boost"));
12 }
13
14 public static void main(String args[]) {
15 JFrame jf = new JFrame("Checkbox Test");
16 jf.getContentPane().add(new CBox());
17 jf.pack();
18 jf.setVisible(true);
19 }
20 }
Overview
The JRadioButton class provides the radio buttons for Swing.
Individually, a JRadioButton simply toggles on and off each time it is
selected, just like a JCheckBox. To obtain the mutual exclusion
behavior of a radio button, add the buttons to a ButtonGroup. A
ButtonGroup is a manager that ensures that only one button is
selected at one time. In the AWT package, this behavior was handled
by the CheckboxGroup class, but Swing uses a more generic
ButtonGroup class to manage all types of buttons.
JRadioButton Example
1 import java.awt.*;
2 import java.awt.event.*;
3 import javax.swing.*;
4
5 public class RadioTest extends JPanel
6 implements ItemListener {
7
8 private JRadioButton tb1, tb2, tb3;
9 private ButtonGroup bg;
10
11 public RadioTest() {
12 setLayout(new GridLayout(4,1));
13 add(new JLabel("Select the audio output device:"));
14 add(tb1 = new JRadioButton("External Speakers"));
15 add(tb2 = new JRadioButton("Internal Speaker"));
16 add(tb3 = new JRadioButton("Headphones"));
17
18 tb1.addItemListener(this);
19 tb2.addItemListener(this);
20 tb3.addItemListener(this);
21
22 // make it behave like a radio interface
23 bg = new ButtonGroup();
24 bg.add(tb1);
25 bg.add(tb2);
26 bg.add(tb3);
27 }
28
29 public void itemStateChanged(ItemEvent ie) {
30 JRadioButton jtb = (JRadioButton)ie.getItem();
31 // have to check, since "unselecting" also
32 // generates an event
33 if (ie.getStateChange() == ItemEvent.SELECTED) {
34 System.out.println("Current output device is: " +
35 jtb.getText());
36 }
37 }
38
Overview
The Swing package also provides a combo box. The closest equivalent
in the AWT package is the Choice button. However, the JComboBox
can be made editable. If it is not editable, it behaves precisely like
the Choice button. If it is editable, however, you have the option of
selecting one of the standard choices or typing in a new value.
JComboBox Example
1 import java.awt.*;
2 import java.awt.event.*;
3 import javax.swing.*;
4
5 public class ComboTest extends JPanel implements ItemListener {
6
7 private JComboBox jcb;
8 private String options[] = { "External Speakers",
9 "Internal Speaker", "Headphones" };
10
11 public ComboTest() {
12 TargetIcon target = new TargetIcon();
13
14 setLayout(new GridLayout(2,1));
15 add(new JLabel("Select the audio output device:"));
16 add(jcb = new JComboBox(options));
17 jcb.setEditable(true);
18 jcb.addItemListener(this);
19 }
20
21 public void itemStateChanged(ItemEvent ie) {
22 System.out.println("Item is: " + ie.getItem());
23 System.out.println("Selectable is: "
24 + ie.getItemSelectable());
25 }
26
27 public static void main(String args[]) {
28 JFrame jf = new JFrame("Combo Test");
29 ComboTest it = new ComboTest();
30 jf.getContentPane().add(it, BorderLayout.CENTER);
31 jf.pack();
32 jf.setVisible(true);
33 }
34 }
Overview
Swing provides a set of menu components. As with other Swing
components, you can add icons to your menus. However, the menu
items themselves are now subclasses of AbstractButton. The
AbstractButton class is the parent class of both buttons and menu
items, so this means that you can use the same event handler for
buttons and menu items.
JMenu Example
1 import java.awt.*;
2 import java.awt.event.*;
3 import javax.swing.*;
4
5 public class MenuTest extends JPanel
6 implements ActionListener {
7
8 public MenuTest() {
9 setLayout(new BorderLayout());
10 Icon cutIcon = new ImageIcon("cut.gif");
11 Icon copyIcon = new ImageIcon("copy.gif");
12 Icon pasteIcon = new ImageIcon("paste.gif");
13
14 JMenuBar jmb = new JMenuBar();
15 JMenu editMenu = new JMenu("Edit");
16 JMenuItem cutItem = new JMenuItem("Cut", cutIcon);
17 editMenu.add(cutItem);
18 cutItem.addActionListener(this);
19
20 JMenuItem copyItem = new JMenuItem("Copy", copyIcon);
21 editMenu.add(copyItem);
22 copyItem.addActionListener(this);
23
24 JMenuItem pasteItem = new JMenuItem("Paste", pasteIcon);
25 editMenu.add(pasteItem);
26 pasteItem.addActionListener(this);
27
28 jmb.add(editMenu);
29 add(jmb, BorderLayout.NORTH);
30
31 add(new JLabel("Look at the Edit menu above"),
32 BorderLayout.CENTER);
33 }
34
35 public void actionPerformed(ActionEvent ev) {
36 Object o = ev.getSource();
37 if (o instanceof AbstractButton) {
38 String command = ((AbstractButton)o).getActionCommand();
Keyboard Accelerators
The JMenu has support for keyboard accelerators.
1 JMenuItem cutItem = new JMenuItem("Cut", cutIcon);
2 JMenuItem copyItem = new JMenuItem("Copy", copyIcon);
3 JMenuItem pasteItem = new JMenuItem("Paste", pasteIcon);
4
5 cutItem.setAccelerator(
6 KeyStroke.getKeyStroke(88, 0, true)); // X
7 copyItem.setAccelerator(
8 KeyStroke.getKeyStroke(67, 0, true)); // C
9 pasteItem.setAccelerator(
10 KeyStroke.getKeyStroke(86, 0, true)); // V
Menu Positioning
You can place menu bars anywhere in your application. This is a
significant change from the menu behavior in AWT. Since the
JMenuBar class is an extension of JComponent, you can position a
JMenuBar anywhere you would add things like buttons or labels; they
are no longer restricted to the physical frames of your application. Be
aware that positioning menu bars at locations other than the top of a
window might confuse users of your application.
Preparation
Read the file README in the labs directory for module 3.
Tasks
Two source files are in the labs directory for module 3. Edit the one
called Translate.java. At each point where you find a line
beginning:
//****
Take care to use the variables that are already declared and in use by
the template.
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
JLabel
JButton
JCheckBox
JRadioButton
ToolTips
JComboBox
JMenu
What other components in the Swing set do you think you could use
now?
Course Map
This module discusses accessibility, Actions, and Keystrokes, which
provide ways to program required behavior in response to user input.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
4-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
4
Relevance
JComponent Accessibility
setAccessibleName(String)
setAccessibleDescription(String)
Actions
Keystrokes
Once you have obtained a KeyStroke object, you can associate that
keyboard activity directly with an Action (or more generally, with an
ActionListener). This is a very convenient mechanism for building
user interface keyboard behavior, and is certainly much simpler than
trapping and dispatching keyboard events longhand.
WHEN_FOCUSED
WHEN_IN_FOCUSED_WINDOW
WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
Preparation
Read the file README.1 in the labs directory for module 4.
Tasks
The file Actions.java contains a template for this exercise. At each
point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Extract the list of Action objects from the JTextPane and add
them to the menu and tool bar
Preparation
Read the file README.2 in the labs directory for module 4.
Tasks
Edit the file Keystroke.java that contains a template for this exercise.
At each point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Obtain the name of each of the Action objects that the JTextPane
provides
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
Course Map
This module discusses the printing features of JDK 1.2, which provide
high-quality printed output.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
5-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
5
Relevance
Printing capability was added to the JDK with the release of JDK1.1,
although the support was really limited to 72 dpi regardless of the
printer. Output is commonly created by redirecting the paint
method so that it renders into the printer, rather than onto the screen.
This method must render the image of the printable onto the supplied
Graphics object. To support this, a PageFormat object is provided that
describes the current page size, margins and so forth. Additionally, the
page indexzero based, within this Printableis supplied.
If the page number indicates a page beyond the range for this
Printable, then the method should return the constant value
NO_SUCH_PAGE. Otherwise, PAGE_EXISTS should be returned. These
constants are defined in the Printable interface. The page index
provided is zero based, and relates to the pages in this Printable, not
the overall page number in the output document as a whole.
1 PrinterJob pj = PrinterJob.getPrinterJob();
2 if (pj.printDialog()) {
3 PageFormat pf = pj.defaultPage();
4 pf = pj.pageDialog(pf);
5
6 pj.setPrintable(ta);
7
8 try {
9 pj.print();
10 System.out.println("Print completed");
11 }
12 catch (PrinterException e) {
13 e.printStackTrace(System.err);
14 System.out.println("Print failed");
15 }
16 }
17 else {
18 System.out.println("Print cancelled");
19 }
Before you can print output, you must create and configure a
PrinterJob object.
You can obtain a PrinterJob object simply by using the static method
getPrinterJob in the PrinterJob class. Next, you supply a
Printable object to describe the required output.
If you click the Cancel button in this dialog box, then the
printDialog method returns false; otherwise, it returns true.
When the PrinterJob has been set up and provided with something
to print, you invoke the actual printing process by calling the print
method of that PrinterJob.
Overview
You have seen a Printable used to define the output for a print job.
You can also arrange for a single PrinterJob to generate its output
from a number of Printable objects. This is achieved using an object
that implements the Pageable interface. A Pageable is a container for
multiple Printable objects and provides a convenient way to gather
the output from multiple parts of a program into one output. Either of
these can represent one or more pages.
Overview (Continued)
A Pageable is a collection of Printable objects. Each Printable
typically represents a page (but may represent a group of pages), and
the Pageable can specify a different page layout for each Printable.
The easiest way to provide a Pageable is to use the Book class, which
implements the Pageable interface, and enables you to append pages
(each is actually described by a Printable object) to it.
Notice that this example is very similar to the earlier one, except that
the Printable object is added to an instance of Book. For each
Printable that is added using the append method, a PageFormat is
specified. This allows separate control over each part of the book.
Preparation
Read the file README in the labs directory for module 5.
Tasks
Edit the file PrintOut.java that contains a template for this exercise.
At each point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Obtain a PrinterJob
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
Course Map
This module introduces the models, views, and controllers paradigm
that is fundamental to many of the more complex Swing components.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
6-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
6
Relevance
MVC Overview
The basis of MVC is that there are three distinct parts that make up
most screen presentations. These are a mathematical model of some
behavior (the model), a visual representation (the view), and a way for
the user to interact with the model and view (the controller).
The models, views, and controllers design pattern has been popular in
object-oriented software development for many years. It is particularly,
although not exclusively, applicable to user interface components, and
we will discuss it in that context.
Controller
open
close
setOpenProportion Open
Close
Interface methods to
physical valve
Controller
open
Physical valve close Open
setOpenProportion
Close
open
close
setOpenProportion
Often, the visual representation and the controller GUI are the same
thing; it can be difficult or inappropriate in many MVC components to
distinguish clearly between these aspects.
Benefits of MVC
You have seen that, in many GUI components, the view and controller
aspects share the same screen space. In such circumstances, it is
common to find a single class that represents both view and controller.
It is important that the model interact with the view and controller
aspects using the same techniques.
In addition to and predating the 1.1 delegation event model, the JDK
APIs provided the Observer interface and Observable class. The
Observable class provides methods that provide for an Observer to
register. After an Observer has registered, its update method is called
by the Observable whenever that Observable changes.
Event Sourcing
When you want to send events from a model, you must first decide
what class of event you want to send.
Generally, you should use an existing event class if one exists that
adequately describes the data you need to pass. If there is no pre-
defined event class that is suitable, you might need to create a new
one. If you do this, it is best to start with an event that is reasonably
close to describing your data; ideally, one that can describe a useful
subset of your data by itself. Then subclass that event and add the new
fields and methods that you require.
The reason for reusing existing events is that it increases the chances of
your model and view being reusable in other code. For example, if you
create a model that fires an ActionEvent, it can be plugged directly
into a GUI that uses ActionEvent to trigger some behavior. If you had
created an entirely new event, you would have had to modify
(perhaps extensively) the existing code before it could interoperate
with your model.
If you do create a new event, you must also make a decision about the
type of listener that you will handle in your view classes. You could
require a listener for events of the parent class, or you could require a
listener that exactly matches your new event class. You could also do
both.
If you accept listeners of the parent event type, then you increase the
chances of reuse. Listeners of that type will not access all the
information about the event, but they might be able to operate usefully
with the limited information available from the parent event class. If
you do not accept parent type listeners, then existing event listeners
cannot be used at all.
If you accept only listeners of the parent type, then listeners that are
actually intended to receive the full information of your event must
use instanceof and a cast before they can access that data.
Handling Listeners
When you have decided on your event and listener types, you must
decide how to distribute the events, and actually code the
add/removeXXXListener methods and a means of firing the events.
The first choice is whether the event firing method should be unicast
or multicast. A unicast event source can send events only to a single
listener. This can be quite limiting, reducing the reusability of your
component. For this reason, unicast event sourcing should not be
considered without a compelling reason.
To dispatch an event to the listeners, you need to create the event and
then call the listeners handler method of each registered listener.
Creating the event should be fairly easy, but depends to some extent
upon the particular event you are dispatching. All events carry a
reference to the originating object. Usually that object will be this.
MVC in Swing
While the 1.1 AWT supports the use of MVC, many of the Swing
components are actually built using it.
Preparation
Read the file README in the labs directory for module 6.
Tasks
The files ButtonController.java, MultiMVC.java,
ProgressView.java, TextView.java, ValveModelImpl.java,
contain a templates for this exercise. At each point where you find a
line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Tasks (Continued)
Implement event handling in a view so that the view responds
correctly to change notification from the model
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
What types of models would you need for components like lists, trees,
tables, and text editors?
Would you ever require different models for any of these components?
Course Map
This module discusses the approach to MVC that is used by most
Swing components, and looks particularly at the JList.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
7-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
7
Relevance
Write code to use the JList class initialized with data in either a
Vector or an Object array
MVC In Swing
Using a JList
This method might seem to embed the data and model inside the
JList, spoiling the MVC design pattern. This is not the case. In fact,
when created in this way, the JList constructs and initializes an
instance of DefaultListModel, and the accessor method getModel
allows you to retrieve the created model for subsequent manipulation
if you wish.
Using a ListModel
These methods allow access to the data, and can be used to register
listeners that will be notified when the data in the model changes.
However, there are no controller methods provided; that is, no
methods are provided that allow modification of the data.
Preparation
Read the file README.1 in the labs directory for module 7.
Tasks
Edit the files TwoLists.java and ListController.java that contain
a template for this exercise. At each point where you find a line
beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Models can have an ad hoc controller interface, as is the case with the
DefaultListModel. In general, however, a consistent approach is
preferable. One possibility is to look for an existing interface (such as
java.util.List) and use that. However, where such an interface is
not available, or perhaps additionally, you can use the action
mechanism to create a controller interface for your model. Recall that
the action mechanism uses a textual command name and invokes the
actionPerformed(ActionEvent) method of the target class. Clearly
not all controller behavior can be readily represented by a single
method taking, in effect, a String argument, but many can. Using this
approach has two additional advantages:
Defining an Action
If you want to create your own actions you will need to implement the
Action interface. As so often is the case, there is an AbstractAction
class that implements most of the mundane work for you.
The value methods enable you to set and retrieve four properties of
the Action. These are the name, long and short descriptions, and icon.
The key by which the property is specified is actually a String. The
Action class defines four constants that should be used for these
strings. These are:
Action.LONG_DESCRIPTION
Action.NAME
Action.SHORT_DESCRIPTION
Action.SMALL_ICON
Model
Actions
(Inner classes in
Model, perhaps)
When you create Action objects, they need some way to perform the
action that they encapsulate. To do this they need to be able to change
the state of the model itself. This can be achieved in a number of ways.
One way is to define the Action classes as inner classes within the
model itself. This ensures that they have full access to the private
member variables of the model. Alternatively you can use package
(default) access on the members and define the Action classes in the
same package, or you can provide the Action objects with a reference
to the model instance, and implement the actionPerformed methods
in terms of the public methods of the model.
Preparation
Read the file README.2 in the labs directory for module 7.
Tasks
Edit the files ActionListController.java,
ActionListModel.java, and ListActions.java that contain a
template for this exercise. At each point where you find a line
beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
Write code to use the JList class initialized with data in either a
Vector or an Object array
Course Map
This module looks at the JTable, and discusses ways to create data
models for it.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
8-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
8
Relevance
JTable Fundamentals
JTable is one of the more complex Swing components, and the MVC
model is clearly evident in its design and use. The main interface that
defines its model is javax.swing.table.TableModel.
A JTable uses a model for columns as well as for the data itself. The
TableColumnModel keeps information about the number, names,
and order of columns, as well as information about their size, margins,
and selection modes.
TableModel TableColumnModel
(AbstractTableModel, (DefaultTableColumnModel)
DefaultTableModel)
TableColumn
TableCellRenderer TableCellEditor
(DefaultTableCellRenderer) (DefaultCellEditor)
Figure 8-1 shows the main classes used by the JTable. TableModel is
an interface that defines the interaction between the JTable and the
data it displays. AbstractTableModel and DefaultTableModel are
classes that implement this interface. As the name suggests, the
AbstractTableModel is an abstract class, while DefaultTableModel
is a concrete subclass of that.
Using a JTable
If you want to specify data for the table cells, but do not need to
provide your own TableModel implementation, you can simply put
the table data into either a two-dimensional array, or a Vector of
vectors. Constructors are provided for the JTable that accept both
these forms, and a DefaultTableModel, initialized with your data,
will be created and installed behind the JTable for you.
If you need more control, you can use a constructor that accepts a
TableModel object, and perhaps specify the ListSelectionModel
and/or TableColumnModel that you need at the same time.
Using an AbstractTableModel
If you need to create your own table model, you can implement the
TableModel interface directly, but in most cases you will subclass
either AbstractTableModel or DefaultTableModel.
If you want to control the way in which the table data is storedfor
example, if the storage is in a databaseand your table model acts as
the interface to that database, then you will probably start with the
AbstractTableModel. If you only want to make changes to
presentational aspects of the modelfor example, making one or more
cells non-editable, but you do not need to control the storage format of
the datathen you will probably simply extend
DefaultTableModel.
Notice that the setValueAt method was not on the list of methods
that must be overridden. If you do not change it, the default form of
this method in the AbstractTableModel does nothing, effectively
making the model immutable.
You can modify this default behavior using the CellRenderer and
CellEditor mechanisms.
Using a CellRenderer
Writing a CellRenderer
Using a CellEditor
Exercise objective Become familiar with the use of JTable, and the
use of the TableModel getColumnClass method.
Preparation
Read the file README in the labs.1 directory.
Tasks
Edit the files MyTable.java and MyTableModel.java in the labs.1
directory. These files contain the template for this exercise. At each
point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Exercise objective Become familiar with the use of the table model
to make particular cells of a table non-editable.
Preparation
Read the file README in the labs.2 directory.
Tasks
Edit the files MyTable.java and MyTableModel.java in the labs.2
directory. These files contain the template for this exercise. At each
point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Preparation
Read the file README in the labs.3 directory.
Tasks
Edit the files MyTable.java, MyTableModel.java, and
ColorRenderer.java in the labs.3 directory. These files contain the
template for this exercise. At each point where you find a line
beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Preparation
Read the file README in the labs.4 directory.
Tasks
Edit the files MyTable.java, MyTableModel.java, and
ColorRenderer.java in the labs.4 directory. These files contain the
template for this exercise. At each point where you find a line
beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
In what other ways could you use a table? Might you be able to use it
as the basis of a spreadsheet? If so, how might you go about this?
Course Map
This module discusses the use of JTree, and editors and renderers.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
9-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
9
Relevance
JTree Foundations
Like the JTable, selections may be specified as either single cell, single
range, or multiple ranges. Constants that define these three
possibilities are defined in the class
javax.swing.tree.TreeSelectionModel.
Editors and renderers are used by the tree too, so two interfaces are
defined, TreeCellEditor and TreeCellRenderer. These are
applied to the entire tree.
When you have all the nodes created, you assemble them into your
tree structure by using the add method of the
DefaultMutableTreeNode itself.
Example
1 import java.awt.*;
2 import javax.swing.*;
3 import javax.swing.tree.*;
4
5 public class TreeTest {
6 private static Object [] nodeNames = { "one", "two", "three",
7 "four", "five", "six", "seven", new Integer(8),
8 new Integer(9), new Float(10) };
9 private static boolean [] leaf = { false, true, true, false,
10 true, true, false, true, true, true };
11
12 public static void main(String args[]) {
13 JFrame jf = new JFrame("Tree Test");
14 DefaultMutableTreeNode [] nodes = new DefaultMutableTreeNode[10];
15 for (int i = 0; i < nodes.length; i++) {
16 nodes[i] = new DefaultMutableTreeNode(nodeNames[i], !leaf[i]);
17 }
18 nodes[0].add(nodes[1]);
19 nodes[0].add(nodes[2]);
20 nodes[0].add(nodes[3]);
21 nodes[0].add(nodes[6]);
22 nodes[0].add(nodes[9]);
23 nodes[3].add(nodes[4]);
24 nodes[3].add(nodes[5]);
25 nodes[6].add(nodes[7]);
26 nodes[6].add(nodes[8]);
27
28 JTree jt = new JTree(nodes[0]);
29 jf.getContentPane().add(jt, BorderLayout.CENTER);
30 jf.pack();
31 jf.setVisible(true);
32 }
33 }
Example (Continued)
The example just listed produces this output.
Notice how the structure correlates to the way the nodes were created
and added to one another.
The method getRoot returns an object that is the root node of the
tree, while the getChild method returns a particular child (by index)
of the specified non-leaf node. The method getChildCount
indicates the number of children for a particular node, and hence the
maximum index for getChild called upon that node.
Editors and renderers operate in the same basic way as for the
JTable. Methods setCellRenderer and setCellEditor are
defined in the JTree class itself and the editor or renderer that is set
using these methods will be used for the entire tree.
Preparation
Read the file README in the labs directory for module 9.
Tasks
Edit the file CompTree.java in the labs directory that contains a
template for this exercise. At each point where you find a line
beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
Course Map
This module discusses the use of JTextPane and styles to provide
complex document editing capabilities.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
10-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
10
Relevance
Bold T F F
Underline / T T
FontSize 12 / 12
Constructing Styles
After you have created the new Style object, you can set the
attributes for it using the StyleConstants convenience methods.
Each method takes the Style (the formal parameter is actually a
MutableAttributeSet, but recall that Style is a subclass of that)
and an argument of suitable type to qualify the attribute in question.
Hence setBold takes a boolean, and setFontSize takes an int.
Applying Styles
After the Style has been created in this way, you can position the
component in the JTextPane simply by putting a placeholder
character (typically a space) into the text buffer and applying the new
Style to that character as a character attribute. Do not apply a
Component style as a logical paragraph style, as this will not work.
Images in JTextPane
You have seen how to insert Component objects into the text of a
JTextPane, and therefore you know that you can insert a Canvas or
JCanvas and use it to place an image into the display. In fact, the
JTextPane supports a lighter weight mechanism for including
pictures in text. This is achieved using Icon objects in a fashion very
similar to that used for displaying Component objects.
Note The content handlers being used by the JTextPane might reject
either components or icons.
Preparation
Read the file README in the labs directory for module 10.
Run the program Editor in the solutions directory. Create new styles
as both root and child styles by entering the name for the new style in
the text field at the top right of the Style editor window.
Tasks
Edit the files Editor.java, FontPane.java, StylePane.java, and
StyleView.java that contain the template for this exercise. At each
point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Tasks (Continued)
Create a JTextPane object using the DefaultStyledDocument
object just created
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
What is the role of a model in the text editing components you have
just studied?
Course Map
This module discusses features of Swing related to programming in a
multi-threaded environment, and for controlling the appearance of
your GUIs.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
11-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
11
Relevance
Would you like more control over the appearance of your programs
when running them with Swing?
Unlike most of the JDK core packages, the Swing classes are generally
not thread safe. There are several reasons for this:
The general rule for correct use of Swing is that only the AWT thread
should access the components. However, there are some exceptions to
this rule.
Three methods in the basic JComponent class are thread safe in all
Swing components: repaint, revalidate, and invalidate. These
methods are thread safe because they are intended to be called by the
application program to trigger redisplay, or recalculation of display by
the AWT thread. As such, the methods themselves actually do not
perform any real work in the caller thread, but send a request to the
AWT thread to perform the required work when it is able.
There are a number of ways that you can communicate with the AWT
thread and arrange for it to do work required by other threads. Two
special mechanisms have been created for Swing, and these will satisfy
most needs.
At a more complex level, you can install a different look and feel for
your program, under program, system administrator, or user control
even while the program is running. If you dont like any of the
available look and feels, you can write your own, although that is not
covered in this course.
Using Borders
The default look and feel for Swing based programs is known as
Metal. Metal is a new look and feel created especially for the Java
programming language. Its design is intended to be reasonably
familiar to anyone and to avoid causing culture shock for users of any
platform.
To install a specific look and feel, simply call the static method
setLookAndFeel in the UIManager class. The method takes a single
argument, which is a String, defining the fully qualified classname of
the look and feel implementation class.
You can determine appropriate class names using two methods in the
UIManager itself. The first determines the platform-independent look
and feel, and the second determines the host platforms own look and
feel. The methods are
UIManager.getCrossPlatformLookAndFeelClassName
UIManager.getSystemLookAndFeelClassName
You can change the current look and feel at any time, including while
the program is running. However, it could be very disconcerting for
the user if the appearance of a program changed entirely without a
very obvious reason. The menu option that is used to trigger the
change should be well enough protected with messages asking Are
you sure? so that the change cannot happen by accident.
Swing permits you to create your own look and feel, either by
subclassing and modifying an existing one, or from scratch. However
this topic is beyond the scope of this course.
Focus Handling
Swing supports the use of an explicit focus manager, and installs one
of its own by default. The Swing focus manager requires the use of
JComponent methods, set/getNextFocusableComponent and
isManagingFocus, that do not exist in the AWT Component class.
Focus Traversal
Normally, focus moves from left to right and top to bottom, in the
same way as words on an English page. The DefaultFocusManager
actually examines the x,y coordinates of each component to derive this
order.
If you want, you can specify that one component follows another in
focus order using the setNextFocusableComponent method of the
JComponent class.
Tasks
Run the program Focus1 and notice how the focus is transferred from
left to right and top to bottom, in the same way as written English.
Preparation
Read the file README.2 in the labs directory for module 11.
Run the program Focus2 in the solutions directory and notice that
focus no longer progresses from left to right and top to bottom.
Tasks
Edit the file Focus2.java that contains a template for this exercise. At
each point where you find a line beginning:
//****
The comment parts of the source will add or complete the following
behavior:
Preparation
Read the file README.3 in the labs directory for module 11.
Run the program Focus3 in the solutions directory for module 11,
and note the location of the focus when the window is first selected.
Do not use a mouse click in the body of the window to select the
whole window for focus, as this will disguise the default focus.
Tasks
Edit the file Focus3.java that contains the template for this exercise.
At each point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Preparation
Read the file README.4 in the labs directory for module 11.
Run the program LnF in the solutions directory for module 11.
Select host look and feel and cross-platform look and feel using the
radio buttons.
Tasks
Edit the file LnF.java that contains the template for this exercise. At
each point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Cause the Swing system to repaint entirely when a new look and
feel has been installed
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
What circumstances might warrant creating your own look and feel?
Course Map
This module discusses a number of useful components that contribute
to a professional user interface.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
12-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
12
Relevance
Do you need user interfaces that allow space to be divided under user
control between two or more regions of the same frame?
Utility Panes
Description
One of the simplest additions you can make to an application to give it
a mature feel is using a graphical file system viewer anytime you need
to browse or choose files. The AWT package included the
FileDialog class which could be opened in Save or Load mode, but
was inflexible. The Swing package contains the JFileChooser.
Example
1 import java.awt.*;
2 import java.awt.event.*;
3 import javax.swing.*;
4
5 public class ChooserTest extends JPanel
6 implements ActionListener {
7
8 private JButton goButton;
9 private JLabel display;
10 private JFileChooser jfc = new JFileChooser();
11
12 public ChooserTest() {
13 goButton = new JButton(Pick File);
14 add(goButton);
15 display = new JLabel(Chosen file will be shown here);
16 add(display);
17
18 goButton.addActionListener(this);
19 }
20
21 public void actionPerformed(ActionEvent ae) {
22 int status = jfc.showOpenDialog(this);
23 if (status == 0) {
24 display.setText(You chose:
25 + jfc.getSelectedFile().getName());
26 }
27 else {
28 display.setText(File chooser was cancelled);
29 }
30 }
31
32 public static void main(String args[]) {
33 JFrame jf = new JFrame(FileChooser test);
34 ChooserTest it = new ChooserTest();
35 jf.getContentPane().add(it, BorderLayout.CENTER);
36 jf.pack();
37 jf.setVisible(true);
38 }
39 }
The JFileChooser
You can apply filters to the JFileChooser too. You can ensure, for
example, that only files with the extension .gif are listed. Filters are
subclasses of the abstract class
javax.swing.filechooser.FileFilter. No filters are provided by
default, but you only need to implement two methods to create a filter.
These methods are:
Description
Owing to its ease of navigation among categorized information, the
tabbed panel has made its way into just about every major computer
application. The JTabbedPane is the Swing answer to this useful
component. With it, you can create a segmented display with very
little effort.
The JTabbedPane
These create empty tabbed panes. The default constructor puts tabs on
the top, but you can use the SwingConstants to put the tabs on the
top, left, bottom or right using the second version of the constructor.
After the pane is created, you will need to add the tabs. Each tab
contains a component. Since only a single component may be specified
when creating the tab, you normally specify a container. The addTab
method takes a text label and a Component reference.
jtp.addTab("System", systemPane);
indexOfComponent(Component comp)
indexOfTab(Icon icon)
indexOfTab(String title)
If you need a reference to the component within a tab, then you can
use the getComponentAt(int index) method.
You also have more direct control over where a tab goes if you need it.
You can use the insertTab method with the following syntax:
public void insertTab(String title, Icon icon,
Component component,
String tip, int index)
JTabbedPane Example
1 import java.awt.*;
2 import java.util.*;
3 import java.awt.event.*;
4 import javax.swing.*;
5
6 public class TabTest extends JPanel
7 implements ItemListener {
8
9 private JTabbedPane jtp;
10 private JCheckBox netCheckBox;
11 private JPanel systemPane = new JPanel();
12 private JPanel audioPane = new JPanel();
13 private JPanel internetPane = new JPanel();
14
15 public TabTest() {
16 setLayout(new BorderLayout());
17 jtp = new JTabbedPane();
18
19 netCheckBox = new JCheckBox(
20 "Internet Connection", true);
21 netCheckBox.addItemListener(this);
22 systemPane.add(netCheckBox);
23
24 audioPane.add(new JLabel("Audio configuration"));
25 internetPane.add(new JLabel("Internet configuration"));
26
27 jtp.addTab("System", systemPane);
28 jtp.addTab("Audio", audioPane);
29 jtp.addTab("Internet", internetPane);
30
31 add(jtp, BorderLayout.CENTER);
32 }
33
Description
If you have interfaces that show multiple distinct areas for use at the
same time, then that interface might benefit from using a split pane.
The JSplitPane comes with two areas, either a top/bottom pair, or a
left/right pair. The main feature of the split pane is that the user can
manually adjust how much space is given to each component at
runtime. Here is an example of JSplitPane, showing the way the
center boundary can be moved.
JSplitPane Example
1 import java.awt.*;
2 import java.awt.event.*;
3 import javax.swing.*;
4
5 public class SplitTest extends JPanel {
6
7 public SplitTest() {
8 JSplitPane sp = new JSplitPane(
9 JSplitPane.HORIZONTAL_SPLIT,
10 new JTextArea("This is one text area"),
11 new JTextArea("This is another text area"));
12 setLayout(new BorderLayout());
13 add(sp, BorderLayout.CENTER);
14 }
15
16 public static void main(String args[]) {
17 JFrame jf = new JFrame("SplitPane Test");
18 SplitTest st = new SplitTest();
19 jf.getContentPane().add(st, BorderLayout.CENTER);
20 jf.pack();
21 jf.setVisible(true);
22 }
23 }
Description
The JScrollPane container enables you to display a component much
larger than the physical area you have to show it in. While the AWT
package includes a scrollable pane as well, the Swing version gives
you quite a bit more control.
Column header
Corners
Vertical scrollbar
Row header
Viewport
Horizontal scrollbar
The viewport and the scrollbars are fairly obvious, but you can also
control the row and column headers and the four corners. The
viewport and headers are all JViewport objects, the scrollbars are
JScrollBar objects, and the four corners can be any Component you
want.
The JScrollPane
Controlling Scrolling
You can also specify what scrolling policies are used:
1 jsp.setVerticalScrollBarPolicy(
2 JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
3 jsp.setHorizontalScrollBarPolicy(
4 JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
Description
The JOptionPane class contains several static methods to display
common warning and error messages in a dialog box.
The JOptionPane
ERROR_MESSAGE
INFORMATION_MESSAGE
WARNING_MESSAGE
QUESTION_MESSAGE
PLAIN_MESSAGE
These types primarily dictate the icon that shows up in your dialog
window. (What icon you get depends on the look and feel youre
currently using.)
As you get comfortable with the message dialogs, you can experiment
with some of the other options available with JOptionPane. You can
create yes/no dialogs and even generic input dialogs.
The JOptionPane
Preparation
Read the file README in the labs directory for module 12.
Run the program MultiEx in the solutions directory for module 12.
Examine all the panes in the tabbed pane, and all the dialog options.
Tasks
Edit the file MultiEx.java that contains the template for this exercise.
At each point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
How would you create displays that have more than two split regions?
Course Map
This module discusses issues that arise when programming for
multiple languages and cultures.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
13-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
13
Relevance
Write code that reads properties from the invoking command line
Since the sources of most Java programs are edited on host machines
using character sets other than Unicode, and most programs run using
keyboard/screen I/O with an underlying operating system that is not
using Unicode, there must be some conversion in both cases.
The JDK provides two main ways to perform the conversion between
platform encoding and Unicode. These are based on the classes
InputStreamReader and OutputStreamWriter. If constructed
with only a stream argument, these classes convert between byte
streams and Unicode Reader and Writer objects on the assumption
that the byte stream is using the platform-local encoding.
When you write code that requires conversion between a byte stream
and a Unicode channel (Reader or Writer) be careful to decide
correctly what type of conversion is required. If the code is
communicating with the host system (keyboard, screen, or files, for
example) then you should probably convert to and from the host
platform encoding, using InputStreamReader and
OutputStreamWriter objects constructed without an explicit byte
encoding. If, however, you are communicating over a network with
hosts for which the byte encoding standard is unknown, then you
must be more careful. If you are writing new code for both ends of the
network, then you can use Unicode or UTF if you want to retain the
maximum flexibility. However, if you are only coding one end of the
system, perhaps a new client for an existing server, then you must
adopt the byte encoding of the other system. More often than not, this
will be ASCII, which is known to the JDK as ISO 8859_1 or 8859_1.
Localizing Code
You can create a property table of your own if you want, in which case
you can initialize it from a file using the
Properties.load(inputStream) method. In fact, this method can be
used to add properties to the system property table. Obtain a reference
to the system properties using the System.getProperties method
and then invoke the load method upon that object.
Locale
Locale is a concept that has been in use for many years now, and is
also supported by the JDK. A locale describes the language and
country in which a program is running. Occasionally it may also
describe the host platform.
ResourceBundle
Overview
You have seen that Properties can be used to input runtime
information, and Locale can be used to identify the host
environment. This still leaves a problem unsolved. How should you
implement the program dependencies that are conditional upon either
Properties or Locale?
Overview (Continued)
A more flexible mechanism for handling general locale dependencies
is embodied in the abstract class java.util.ResourceBundle. A
ResourceBundle is similar to a Hashtable in that it organizes a
collection of Object instances indexed by a String key field. For
each locale that is to be supported by the program, a new
ResourceBundle class is created. The name of the class should
reflect the Locale for which it is intended; for example,
Support_en_GB.
Provided that these naming conventions are used, you can obtain the
appropriate ResourceBundle for your programs current locale by
calling the static method getBundle(String rootname) in the
ResourceBundle class. The rootname provided should be the fully
qualified base class name, so that the locale description parts can be
added by simple extension.
You can load a ResourceBundle for a specific locale, rather than the
default. This might be appropriate in response to a command line
option, since it would enable the user to override the system default.
ResourceBundle
Using a ResourceBundle
When you have located the correct ResourceBundle for your locale,
you can obtain data from it using three getXXX methods. Each
method takes a String argument which is the name of the particular
resource that you want to retrieve. Depending upon whether you are
trying to retrieve a String, an array of String objects, or some other
class, you should use the methods getString, getStringArray, or
getObject. Note that since arrays are actually Object instances this
third option is suitable for any data type, although it will require you
to cast the returned value appropriately.
ResourceBundle
Creating a ResourceBundle
There are several ways to obtain a suitable ResourceBundle for use in
a program. You can subclass the (abstract) class ResourceBundle, in
which case you must implement two methods. These are
handleGetObject(String key) and getKeys. The first of these
implements the actual retrieval mechanism, while the second must
return an Enumeration that lists all the keys that are known to this
particular bundle.
ListResourceBundle
Formatting Messages
Overview
Messages that are used by a Java program often need double
configuration. Different message text may be needed to support
different languages, and frequently those messages also need to have
runtime values substituted into them. For example a program might
need to report Today is January first or, in a different locale Au jour
dhui cest le premier Janvier. Clearly both messages contain a
constant part, and also two variable parts. To make it more
complicated, the variable parts occur in different orders.
Formatting Messages
Formatting Messages
Object [] values = {
bundle.getString("colorname"),
new Integer(balloonCount),
new Date()
};
Formatting Messages
time
date
number
choice
You will see in the following pages how each of these options can take
additional text to control the detail of the formatting involved.
Date Formatting
The time and date placeholder options may take any of the sub-
modifiers: short, medium, long, and full, or an explicit
pattern describing exactly how the date should be shown. Each of
these four options will produce output that is dependent upon the
current locale, including using local languages for day and month
names and so forth. The full documentation on the explicit pattern
format is given in the documentation for the class
java.text.SimpleDateFormat.
Numeric Formatting
Choice Formatting
Nested Formatting
Overview
Formats may be nested, so that one format refers to other subformats.
This can be useful with ChoiceFormat objects, since they only
perform limited formatting themselves, and you will usually need to
paste their output into another string. It is also a useful technique for
reusing formats and templates in multiple situations, and for breaking
down very complex formats into more manageable chunks.
Example
import java.text.*;
MessageFormat dirMsg =
new MessageFormat("In directory {0} {1}");
Format [] dirForms = { null, plural };
dirMsg.setFormats(dirForms);
Object [] dirArgs = { "tools", null };
for (int fileCount = 0; fileCount < 4; fileCount++) {
dirArgs[1] = new Integer(fileCount);
System.out.println(dirMsg.format(dirArgs));
}
MessageFormat collected =
new MessageFormat("My friend {0} tells me {1}");
Format [] collectedForms = { null, dirMsg };
collected.setFormats(collectedForms);
Object [] collectedArgs = { "Ruth", dirArgs };
System.out.println(collected.format(collectedArgs));
}
}
Preparation
Read the file README in the labs directory for module 13.
Tasks
Edit the files Messages.java and WeatherMessages.java that
contains the template for this exercise. At each point where you find a
line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
Write code that reads properties from the invoking command line
Course Map
This module discusses the techniques needed to create new
components.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
14-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
14
Relevance
Component Requirements
Once you have decided to create a new component, there are three key
features that you will need to program. These are the look, the
feel, and the event behavior.
Event behavior. The events that the component issues are used to
program its interactions with other components.
Because of the look and feel issue, and the fact that it is usually easier,
extend existing Swing components, rather than start from scratch,
wherever possible.
Lightweight Components
Event Handling
Once these decisions had been made, you need to write some
methods. These have been seen already, but they are shown here for
reference. The methods you must write are the
add/removeXXXListener methods, and a convenience method for
firing the events.
Recap
You need to add code to support the adding of listeners, and for firing
events to those listeners. This was discussed in detail in on page 6-
1 in Module 6, Models, Views, and Controllers but for convenience
the template code for these key aspects is shown here too.
1 import java.awt.*;
2 import java.awt.event.*;
3 import com.sun.java.swing.*;
4 import java.util.*;
5
6 public class XYInput extends JComponent {
7 private Vector listeners = new Vector();
8 private Point clickedAt;
9
10 public XYInput() {
11 enableEvents(AWTEvent.MOUSE_EVENT_MASK);
12 setPreferredSize(new Dimension(256, 256));
13 }
14
15 public XYInput(Dimension d) {
16 this();
17 setPreferredSize(d);
18 }
19
20 public XYInput(int w, int h) {
21 this(new Dimension(w, h));
22 }
23
24 protected void processMouseEvent(MouseEvent ev) {
25 if (ev.getID() == MouseEvent.MOUSE_CLICKED) {
26 clickedAt = ev.getPoint();
27 XYEvent e = new XYEvent(this, clickedAt);
28 sendEvent(e);
29 repaint();
30 }
31 super.processMouseEvent(ev);
32 }
33
Preparation
Read the file README in the labs directory for module 14.
Tasks
Edit the file XYKeyInput.java that contains the template for this
exercise. At each point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Check for the nature of a key event, both the key value and
whether this is a key being pressed or released
Take part in focus traversal when the user presses the Tab key to
select the next focusable component
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
What sort of custom components can you think of that you might be
called upon to create?
Course Map
This module discusses the implementation of copy-and-paste and
drag-and-drop features in user interfaces.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
15-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
15
Relevance
Discussion Will your users accept an interface that does not support
cut-and-paste? How will they feel about a drag-and-drop feature?
Data Types
There are two main mechanisms for users to initiate data transfer
using the GUI. These are copy-and-paste, and drag-and-drop. The
most fundamental aspect of both is that the data to be transferred must
be packaged in a format that is comprehensible to the receiver.
Often, the originator of a GUI data transfer might be able to offer its
data in multiple formats. For example, dragging from a JTextPane
could offer a Document object, which would fully represent all detail of
the source data, including styles; a String, which would retain full
Unicode characters, but not the styles; or plain (ASCII) text which
would lose any non 8-bit characters. Clearly this observation involves
a preference order, the data are best represented in a particular way,
but useful information can be extracted by looking at the data in some
other way.
In the same way that the source of a data transfer might offer multiple
data types, with a preference ordering, so the receiver will also have a
list of acceptable types, and a preference order associated with them.
Whenever a transfer is attempted, the source and destination must
agree on the format that the transfer is to take place using. If no
common types exist, then the transfer cannot take place.
Overview
When a component needs to obtain data from the clipboard, it should
follow this sequence of operations. Each step references a line or lines
in the example on page 15-8.
3. Obtain the list of data flavors that can represent the clipboard data
(line 5).
5. Extract and use the data using the chosen flavor (lines 8 and 11).
Example
1 import java.awt.datatransfer.*;
2 // this is a Component instance
3 Clipboard c = getToolkit().getSystemClipboard();
4 Transferable t = c.getContents(this);
5 DataFlavor [] flavors = t.getTransferDataFlavors();
6 for (int i = 0; i < flavors.length; i++) {
7 try {
8 Object o = t.getTransferData(flavors[i]);
9 System.out.println("Flavor " + i + " gives "
+ o.getClass().getName());
10 if (o instanceof String) {
11 text.setText((String)o);
12 }
13 }
14 catch (Exception ex) {
15 ex.printStackTrace();
16 }
17 }
Note This code fragment assumes that the this object is a text
component of some sort.
Copy to Clipboard
Overview
To put data into the system clipboard, a component should follow this
sequence of operations. Each step references a line in the example on
page 15-10.
2. Create a Transferable object that represents the data and the forms
in which it can be viewed (line 6).
Overview (Continued)
When setting the data in the clipboard, you need to provide a
ClipboardOwner object. ClipboardOwner is an interface that
defines a method void lostOwnership(Clipboard,
Transferable). If some other program writes into the clipboard, the
lostOwnership method will be called, allowing you the chance to
preserve the Transferable you created, or otherwise react as you
might need. You might want to use this to abandon your reference to
the data, allowing it to be garbage collected.
Example
1 import java.awt.datatransfer.*;
3 Clipboard c = getToolkit().getSystemClipboard();
4 // Create a Transferable to put into the clipboard
5 // StringSelection is simplest, and pre-defined
6 StringSelection ss = new StringSelection(text.getText());
7 c.setContents(ss, this);
Implementing Transferable
DataFlavor [] getTransferDataFlavors()
boolean isDataFlavorSupported(DataFlavor)
The first of these methods must return the data, in the format
requested. If the requested flavor is not possible, then an
UnsupportedFlavorException should be thrown.
Preparation
Read the file README.1 in the labs directory for module 15.
Run the program CutPaste in the solutions directory. Use the cut
and paste buttons, and cut and paste from other programs in your
system. This will show you the required behavior for your solution.
Tasks
Edit the file CutPaste.java that contains the template for this
exercise. At each point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Drag-and-Drop
X Windows Mechanisms
On UNIX systems running X Windows, a potential complication
arises. There are two distinct drag-and-drop mechanisms defined for X
Windows, and they are incompatible. The drag-and-drop mechanism
used by the JDK is compatible only with the Motif/CDE system. If you
use OpenLook window manager or OpenLook programs, drag-and-
drop between those systems and Java programs will not work.
Drag-and-Drop Actions
Drag-and-drop can perform more than one action. You might copy a
file, or you might move it. You might, in some systems, even create a
link or shortcut to the file. These different possibilities are referred
to as actions. Usually, the user indicates the desired action by using
keys, such as Shift, Control and so forth, during the drag.
There are three distinct parts of the drag-and-drop system that might
influence the action that is performed; these are the drag source, drag
target, and the user. Ideally, the final action should be the one chosen
by the user. However, if the user attempts to invoke an action that the
source cannot support, then the action will be modified accordingly. In
such a case, the mouse cursor will indicate what action is being
prepared. Similarly, if the proposed action is unacceptable to the drop
target, then it can be rejected.
Overview
The DropTarget class builds an association between a Component and
a DropTargetListener. The constructor for a DropTarget takes the
Component and DropTargetListener as arguments. Note that
DropTargetListener is an interface, so it is quite possible for both
these constructor arguments to be references to the same object.
These methods are the target of callbacks that are made as the drag
proceeds. The most important of these is the drop method, which is
called when the user finally commits the drop operation over the
Component that is associated with this DropTargetListener.
As the drag proceeds the mouse cursor will indicate if the proposed
drop is being accepted or rejected. Because this mouse behavior is
triggered by the acceptDr?? and rejectDr?? methods it is important
that you call them appropriately.
As with all the listener methods, the drop method must indicate if this
drop operation is valid by calling the acceptDrop or rejectDrop
method of the DropTargetDropEvent.
Before the drop method completes, you must also call the method
dropComplete on the DropTargetDropEvent to indicate that this drag-
and-drop operation is now completed.
Example
1 import java.awt.*;
2 import java.awt.dnd.*;
3 import java.awt.datatransfer.*;
4 import java.io.*;
5
6 public class DroppableList extends List
7 implements DropTargetListener{
8
9 public DroppableList() {
10 // this is both target component and listener
11 new DropTarget (this, this);
12 }
13
14 private void validateDrag(DropTargetDragEvent e) {
15 int action = e.getDropAction();
16 if (action == DnDConstants.ACTION_MOVE) {
17 e.acceptDrag(action);
18 }
19 else {
20 e.rejectDrag();
21 }
22 }
23
24 public void dragEnter(DropTargetDragEvent e) {
25 validateDrag(e);
26 }
27
28 public void dragOver(DropTargetDragEvent e) {
29 validateDrag(e);
30 }
31
32 public void dropActionChanged(DropTargetDragEvent e) {
33 validateDrag(e);
34 }
35
36 public void dragExit(DropTargetEvent e) { }
37
Example (Continued)
38 public void drop(DropTargetDropEvent e) {
39 int action = e.getDropAction();
40 Transferable tr = e.getTransferable();
41 if ((action == DnDConstants.ACTION_MOVE) ||
42 tr.isDataFlavorSupported(DataFlavor.stringFlavor)) {
43 e.acceptDrop(action);
44 try {
45 String s = (String)tr.getTransferData (
46 DataFlavor.stringFlavor);
47 add (s);
48 e.dropComplete(true);
49 }
50 catch (Exception ex) {
51 e.rejectDrop();
52 }
53 }
54 else {
55 e.rejectDrop();
56 }
57 }
58 }
Overview
A DragSource object serves two main functions. It may be used to
create a DragGestureRecognizer. A DragGestureRecognizer
recognizes a sequence of actions at the GUI (such as a mouse drag)
that constitute the start of a drag operation. In many cases, the
gestures that initiate a drag operation are well defined for the host
platform. For this reason a default recognizer that responds
appropriately for the host platform is available. Obtain a reference to
the platforms gesture recognizer by using the method
createDefaultDragGestureRecognizer in the DragSource object.
Overview (Continued)
Once the drag is started, the DragGestureRecognizer calls the
method dragGestureRecognized in the DragGestureListener
object. This method then starts the drag itself. This is achieved by
calling the startDrag method of the DragSource object. There are a
number of overloaded versions of this method, but the most likely one
to call expects four arguments:
Example
1 import java.awt.*;
2 import java.awt.dnd.*;
3 import java.awt.datatransfer.*;
4
5 public class DraggableLabel extends Label
6 implements DragSourceListener, DragGestureListener {
7
8 DragSource dragSource;
9 public DraggableLabel(String s) {
10 super(s);
11 dragSource = new DragSource();
12 dragSource.createDefaultDragGestureRecognizer(
13 this, DnDConstants.ACTION_MOVE, this);
14 }
15
16 public void dragGestureRecognized(DragGestureEvent e) {
17 StringSelection text = new StringSelection(getText());
18 // specify null for the DragSourceListener if you are
19 // not interested in the callbacks.
20 dragSource.startDrag(
21 e, DragSource.DefaultCopyDrop, text, this);
22 }
23
24 // if no callbacks needed, you do not have to implement
25 // DragSourceListener at all.
26 public void dragDropEnd(DragSourceDropEvent e) { }
27 public void dragEnter(DragSourceDragEvent e) { }
28 public void dragExit(DragSourceEvent e) { }
29 public void dragOver(DragSourceDragEvent e) { }
30 public void dropActionChanged(DragSourceDragEvent e) { }
31 }
Preparation
Read the file README.2 in the labs directory for module 15.
Tasks
Edit the file DragDrop.java that contains the template for this
exercise. At each point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
What reusable components can you create for use with GUI data
transfer?
Course Map
This module discusses the use of the GridBagLayout in the
production of complex user interfaces.
Swing Introduction
Introduction Swing Foundations
Printing
Text in Swing
Text Editing
with Swing
16-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
16
Relevance
Can you create all reasonable layouts using only Flow, Grid, and
Border layouts?
Layout Managers
This course assumes you know about the basic three layout managers,
FlowLayout, GridLayout, and BorderLayout. If you are unsure about
any of these, ask your instructor if you can discuss them during a
break.
If you do know the basic three layout managers, you will also know
that they are somewhat limited in their capabilities, and that it can be
quite hard work, often involving many nested panels, to produce a
layout that is useful in a production program. This module looks at the
GridBagLayout, which is more powerful.
The GridBagLayout
Where a component does not fill the entire region allocated to it, its
position within that region can be controlled using a concept called
anchor. Anchor takes one of nine values. Eight of these values are
compass points, NORTH, SOUTHWEST and so on. The ninth is CENTER. If
a component has its natural size and an anchor of NORTHWEST, then it
will be positioned at the top left of its allocated region.
gridx and gridy. These integer fields are used to specify the row
and column numbers at the top left of the components region.
They are effectively the components coordinates.
fill. This field indicates how the component is sized within its
region. Values for this field are constants in the
GridBagConstraints class. The four symbolic values are: NONE,
HORIZONTAL, VERTICAL, BOTH.
Note Avoid setting weights on the same row or column for more
than one component. Doing so will simply serve to confuse anyone
reading the program.
Design Steps
When designing with a GridBagLayout, a good approach is this.
2. Make another sketch with the window enlarged, and plan how
you want the extra space to be allocated.
4. Decide how the extra space has been allocated. In some cases, it
might be easiest to do this in terms of percentages. Once you have
determined your percentages, you can use these as weightx and
weighty values directly (even if they do not finally add up to
100).
9. You now have all the key values required to set up your layout.
All that remains is to add the components and allocate the weights
to the rows and columns. You should choose one component for
each row and one component for each column to supply the
weight values. These components should be chosen so that they
only occupy one column if they are providing weightx, and one
row if they are providing weighty. If possible, use components on
the top row to specify weightx and components in the left column
to specify weighty.
First draw the two sketches, showing the basic and expanded sizes of
the proposed layout.
Extra column
0 1 2 3 4
Loose component
Next, draw on the gridlines and identify how the stretch is allocated.
There are a number of points to note here.
Example (Continued)
The expanded version brings out the existence of an extra column,
which is not really noticeable until the display is expanded. You would
be unlikely to recognize this columns existence in the unexpanded
diagram.
The loose component in column 0, third down, does not match any
of the grid cell boundaries. Rather, it appears to overlap rows 4 and 5.
The component actually is located in a region that extends over rows 3
through to 6 inclusive, and is vertically centered in that region.
Rows 0, 1, and 6 do not change size, but rows 2 through 5 all stretch
equally.
Example (Continued)
2 3 4 5
9
6 7
10
11
12
Example (Continued)
2 3 4 5
9
6 7
10
11
12
The next stage in designing the layout is to determine the fill and
anchor values for the components.
The fill value should be BOTH for all components that take the full size
of their available regions. This is important even if the region does not
stretch. For example, the cells occupied by components 8, 9, 10, and 11
do not stretch horizontally, so you might think that a horizontal
component of fill was unnecessary. However, if you only specify a fill
of VERTICAL, you will find that the components are given their
preferred sizes, and since their labels are shorter, components 8 and 9
will be slightly smaller than components 10 and 11.
So, in this example, the only component that is not set to fill BOTH is
component 6. This should have a fill value of HORIZONTAL, to ensure
that it takes up the full width of its region.
Example (Continued)
0 1 1 2 3 4
0 1
1 2 3 4 5
2 8
3 9
7
6
4 10
5 11
6 12
For this example, the stretch is in columns 1 and 3, and rows 2 through
to 5.
Example (Continued)
Components 8, 9, 10, and 11 are suitable to apply the vertical weight
values for rows 2 through to 5, and component 3 is appropriate to
apply the horizontal weight for column 1. However, there is no
obvious component with which a horizontal weight can be applied to
column 3.
Example (Continued)
Example (Continued)
The main part of the program from this example, with the values used
in the GridBagConstraints, is shown here.
1 import java.awt.*;
2 import javax.swing.*;
3
4 public class ExampleGB {
5 public static void main(String args[]) {
6 JFrame f = new JFrame("GridBag Example");
7 Container c = f.getContentPane();
8 c.setLayout(new GridBagLayout());
9 GridBagAdder.add(c, new Canvas(), 3, 2, 1, 1, 1, 0,
10 GridBagConstraints.NONE, GridBagConstraints.CENTER);
11 GridBagAdder.add(c, new JButton("1"), 0, 0, 5, 1, 0, 0,
12 GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER);
13 GridBagAdder.add(c, new JButton("2"), 0, 1, 1, 1, 0, 0,
14 GridBagConstraints.BOTH, GridBagConstraints.CENTER);
15 GridBagAdder.add(c, new JButton("3"), 1, 1, 1, 1, 1, 0,
16 GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER);
17 GridBagAdder.add(c, new JButton("4"), 2, 1, 1, 1, 0, 0,
18 GridBagConstraints.BOTH, GridBagConstraints.CENTER);
19 GridBagAdder.add(c, new JButton("5"), 3, 1, 2, 1, 0, 0,
20 GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER);
21 GridBagAdder.add(c, new JButton("6"), 0, 2, 1, 4, 0, 0,
22 GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER);
23 GridBagAdder.add(c, new JButton("7"), 1, 2, 3, 4, 0, 0,
24 GridBagConstraints.BOTH, GridBagConstraints.CENTER);
25 GridBagAdder.add(c, new JButton("8"), 4, 2, 1, 1, 0, 1,
26 GridBagConstraints.BOTH, GridBagConstraints.CENTER);
27 GridBagAdder.add(c, new JButton("9"), 4, 3, 1, 1, 0, 1,
28 GridBagConstraints.BOTH, GridBagConstraints.CENTER);
29 GridBagAdder.add(c, new JButton("10"), 4, 4, 1, 1, 0, 1,
30 GridBagConstraints.BOTH, GridBagConstraints.CENTER);
31 GridBagAdder.add(c, new JButton("11"), 4, 5, 1, 1, 0, 1,
32 GridBagConstraints.BOTH, GridBagConstraints.CENTER);
33 GridBagAdder.add(c, new JButton("12"), 0, 6, 5, 1, 0, 0,
34 GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER);
35 f.pack();
36 f.setVisible(true);
37 }
Example (Continued)
Supporting the code on the previous page is this inner class. It
provides the add method that simplifies setting up the
GridBagConstraints values.
38 static class GridBagAdder {
39 // OK to reuse this as we overwrite all elements every time
40 // Note that this is not threadsafe however!
41 static GridBagConstraints cons = new GridBagConstraints();
42 public static void add(Container cont,Component comp,int x, int y,
43 int width,int height,int weightx,int weighty,
44 int fill,int anchor) {
45
46 cons.gridx = x;
47 cons.gridy = y;
48 cons.gridwidth = width;
49 cons.gridheight = height;
50 cons.weightx = weightx;
51 cons.weighty = weighty;
52 cons.fill = fill;
53 cons.anchor = anchor;
54 cont.add(comp, cons);
55 }
56 }
57 }
To help with this situation, you can use the value RELATIVE to
indicate that a component should be positioned just to the right, or just
underneath, the one previously added.
Careful use of these shorthand features can make code easier to write
and smaller, which can make it easier to read. However, in some
situations, the fact that their use makes the layout dependent upon the
order of adding components might actually make code more difficult
to read.
Preparation
Read the file README in the labs directory for module 16.
Run the program Layout in the solutions directory for module 16.
Resize the window and observe the dynamic behavior of this layout.
This shows you how your layout should behave.
Tasks
Edit the file Layout.java that contains a template for this exercise. At
each point where you find a line beginning:
//****
The commented parts of the source will add or complete the following
behavior:
Exercise Summary
Discussion Take a few minutes to discuss what experiences, issues,
or discoveries you had during the lab exercises.
Experiences
Interpretations
Conclusions
Applications
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
Are there any layout effects that you cannot handle using the layout
managers discussed in this module?
A-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
A
Relevance
Describe the JDK 1.1 event delegation model and write code based
on it to allow a user interface Input component, such as a button,
to cause code of your choice to be executed
This new model, sometimes called the Delegation model, is now used
in AWT, the JavaBeans component model, and Swing. In fact, in Swing
the delegation model is the only permissible model.
Overview
An event is an object that encapsulates information about something
that has happened. It might be better called an event descriptor, but
convention has long used the term event. Events are used to pass
information about all kinds of occurrences, not just GUI activity.
However, the great majority of events used in most programs relate to
user interfaces, and as such the ultimate cause of such events is
something the user did with the mouse or keyboard.
Note This compares favorably with the JDK 1.0 model which had
every user interface event processed by each container in a GUI
hierarchy by default.
To work with pre-defined events, such as those in Swing and the AWT,
you need to be able to do two things.
First, you must be able to register your listener with the source of an
event.
You can tell that an object issues events because it will have a method
of this form:
public void add???Listener(???Listener l)
Event Classes
Overview
The AWT system and Swing use many pre-defined events. The
majority of these are in the package java.awt.event.
Before continuing on to the next appendix, check that you are able to
accomplish or answer the following:
Describe the JDK 1.1 event delegation model and write code based
on it to allow a user interface Input component, such as a button,
to cause code of your choice to be executed
B-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
B
Relevance
Printing B-3
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
B
AWT Printing
Overview
Printing with the AWT (JDK 1.1) mechanism is quite simple. Printed
output is generated when something draws onto a special Graphics
object that is associated with the printer.
Note The paintAll and printAll methods are used to render not
just the individual component, but also any contained components in
a container.
Overview (Continued)
It is common and simple to implement the print method by simply
invoking the paint method, like this:
1 public void print(Graphics g) {
2 paint(g);
3 }
Note This might not work with heavyweight components, where the
drawing is delegated to the peer.
This would result in the printed output closely matching the screen
version; an equivalent approach can be used for printAll using
paintAll. If you wish to have the printed version look different
(perhaps using different colors, textures, or fonts) then you would
implement a more complex print method.
If you are creating your own print button in a user interface then you
need to construct a suitable Graphics and either call the print or
printAll method. A Graphics object that refers to the printer, rather
than to the screen is obtained by the following steps:
Printing B-5
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
B
AWT Printing
Overview (Continued)
4. For each successive output page that is required, call the dispose
method on the previous Graphics, and then call getGraphics
on the PrintJob again.
5. Finally, when all required pages have been output, call the end
method of the PrintJob. This causes the spooled output to be
submitted as a job to the printer.
Example
1 import java.awt.*;
2 import javax.swing.*;
3 import java.awt.event.*;
4
5 public class AWTPrint {
6 public static void main(String args[]) {
7 final JFrame f = new JFrame("AWTPrint");
8 JButton b = new JButton("Print");
9 final JTextArea ta = new JTextArea("Some example text", 10, 40);
10 f.getContentPane().add(b, BorderLayout.NORTH);
11 f.getContentPane().add(ta, BorderLayout.CENTER);
12
13 b.addActionListener(
14 new ActionListener() {
15 public void actionPerformed(ActionEvent e) {
16 Toolkit k = ((Component)(e.getSource())).getToolkit();
17 PrintJob pj = k.getPrintJob(f, "Print Job", null);
18 if (pj != null) {
19 while (morePages()) { // ficticious boolean method
20 Graphics g = pj.getGraphics(); // get a page
21 g.setClip(new Rectangle(0, 0, 72*9, 72*11));
22 ta.paintAll(g);
23 Font font = new Font("Serif", Font.ITALIC, 24);
24 g.setFont(font);
25 g.setColor(Color.black);
26 g.drawString("Page 1", 40, 440);
27 g.dispose();
28 g = pj.getGraphics();
29 g.setFont(font);
30 g.setColor(Color.black);
31 g.drawString("Page 2", 40, 440);
32 g.dispose();
33 }
Printing B-7
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
B
AWT Printing
Example (Continued)
34 pj.end(); // submit whole job
35 }
36 }
37 }
38 );
39
40 f.setSize(400, 400);
41 f.setVisible(true);
42 }
43 }
In some cases, you might find that a heavyweight component does not
render properly if you simply call its paint method. This can happen
if the component relies entirely on the peer to do the drawing. This is
not a problem with the distribution AWT components, however.
Printing B-9
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
B
Check Your Progress
Before continuing on to the next appendix, check that you are able to
accomplish or answer the following:
C-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
C
Relevance
Install new fonts, and configure font aliases for use in either
Solaris or Microsoft Windows JDK/JRE environments
Adding Fonts
The JVM runtime system allows you to install as many fonts into a
runtime as you need, although by default only four basic families are
configured. Your programs can determine what font families are
available by using the getFontlist method of the Toolkit class.
If you need to, you can add new fonts. This might be necessary to
allow you to test a program under a locale that is different from your
normal one. You can do two things; you can add aliases, which might
allow you to get a program working even if it requests a font family
that you do not have; and you can install new fonts for an existing
family, or install entirely new fonts.
Font Configuration
Most font files do not contain enough glyphs to cover the entire
Unicode character set; indeed, most programs running in most locales
will never need the entire set. Consequently the JVM runtime systems
font definition mechanism allows you to specify several font files to be
used for a single font family.
For example, to specify the primary font file for use by the font family
called serif you might make an entry of this form:
serif.0=Times New Roman,ANSI_CHARSET
Supporting files would use entries serif.1, serif.2 and so forth. The
numbering indicates the order in which fonts are checked to see if they
support the required glyph. If a character is available in more than one
of the specified fonts, the lowest-numbered one will be used.
Note that the digit (1 in this example,) should match the digit in the
original declaration. The fully qualified classname indicates a class
(which must be available to the runtime, on CLASSPATH) that can be
used to convert the font indexes to and from Unicode values.
First, fonts in a Solaris system are specified using the X11 system. This
creates font names that are very long, using hyphens to separate
different parts of the name, so that each part specifies a particular
feature, such as the point size, or family name. Also X11 fonts are not
generally scalable; instead, the Java runtime needs to load a different
font file for each different point size that is requested. Your entry in the
font.properties file needs to include a %d to indicate the part of
the font name that should be substituted with the size.
X11 fonts do not use the Unicode character set indices. For this reason,
the need to convert is assumed, and you do not need to specify
NEED_CONVERTED. Also, the fontcharset entry that specifies how to
convert the indices is required.
Before continuing on to the next module, check that you are able to
accomplish or answer the following:
Install new fonts, and configure font aliases for us in either Solaris
or Microsoft Windows JDK/JRE environments
D-1
Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. Enterprise Services November 1998, Revision A
D
Relevance
Undo/Redo Features
The UndoableEdit class has two key methods, undo and redo,
which should reverse or restore the edit that the event describes if
possible and appropriate.
1 import java.awt.*;
2 import java.awt.event.*;
3 import javax.swing.*;
4 import javax.swing.event.*;
5 import javax.swing.text.*;
6 import javax.swing.undo.*;
7
8 public class Undoer {
9 public static void main(String args[]) {
10 JFrame frame = new JFrame("Undoable Edits");
11 JTextPane pane = new JTextPane();
12 frame.getContentPane().add(pane, BorderLayout.CENTER);
13 DisplayableUndoManager undoer = new DisplayableUndoManager(pane);
14 frame.getContentPane().add(undoer, BorderLayout.SOUTH);
15 frame.pack();
16 frame.setVisible(true);
17 }
18 }
19
20 class DisplayableUndoManager extends JPanel
implements UndoableEditListener {
21 private UndoManager undoManager = new UndoManager();
22 private JTextField nextUndo = new JTextField("", 30);
23 private JTextField nextRedo = new JTextField("", 30);
24 private JButton undoButton = new JButton("Undo");
25 private JButton redoButton = new JButton("Redo");
26 private JPanel leftPanel = new JPanel();
27 private JPanel rightPanel = new JPanel();
28
29 public DisplayableUndoManager(JTextComponent editSource) {
30 leftPanel.setLayout(new GridLayout(2, 1));
31 leftPanel.add(undoButton);
32 leftPanel.add(redoButton);
33
34 rightPanel.setLayout(new GridLayout(2, 1));
35 rightPanel.add(nextUndo);
36 rightPanel.add(nextRedo);
37
38 setLayout(new BorderLayout());
39 add(leftPanel, BorderLayout.WEST);
40 add(rightPanel, BorderLayout.CENTER);
41
42 nextUndo.setEnabled(false); // just for viewing.
43 nextRedo.setEnabled(false); // ditto
44
45 editSource.getDocument().addUndoableEditListener(this);
46 undoButton.addActionListener(
47 new ActionListener() {
48 public void actionPerformed(ActionEvent ev) {
49 undoManager.undo();
50 refresh();
51 }
52 }
53 );
54
55 redoButton.addActionListener(
56 new ActionListener() {
57 public void actionPerformed(ActionEvent ev) {
58 undoManager.redo();
59 refresh();
60 }
61 }
62 );
63 }
64
65 public void undoableEditHappened(UndoableEditEvent ev) {
66 undoManager.undoableEditHappened(ev);
67 refresh();
68 }
69
70 private void refresh() {
71 nextUndo.setText(undoManager.getUndoPresentationName());
72 nextRedo.setText(undoManager.getRedoPresentationName());
73 undoButton.setEnabled(undoManager.canUndo());
74 redoButton.setEnabled(undoManager.canRedo());
75 }
76 }
Notice that the real work is all done in the UndoManager instance that
is created within this example. UndoableEditEvent objects are
passed to that from the Document, and the undo and redo methods
work as expected, with the simple proviso that they are only called if
the UndoManager reports canUndo or canRedo as true respectively.
Before continuing on to the next appendix, check that you are able to
accomplish or answer the following: