![]() |
James Thornton |
| Internet Business Consultant | Call Toll Free: 1 (800) 409-2501 |
| About James | My MySpace | Internet Marketing | Enron Loophole | Lock Bumping | Contact Me |
|---|
The original design goal of the graphical
user interface (GUI) library in Java 1.0 was to allow the programmer to build a
GUI that looks good on all platforms.
That
goal was not achieved. Instead, the Java 1.0
Abstract Window Toolkit (AWT) produces a GUI that
looks equally mediocre on all systems. In addition, it’s restrictive: you
can use only four fonts and you cannot access any of the more sophisticated GUI
elements that exist in your operating system. The Java 1.0 AWT programming model
is also awkward and non-object-oriented. A student in one of my seminars (who
had been at Sun during the creation of Java) explained why: the original AWT had
been conceptualized, designed, and implemented in a month. Certainly a marvel of
productivity, and also an object lesson in why design is important.
[ Add Comment ]
The situation improved with the Java 1.1
AWT event model, which takes a much clearer, object-oriented approach, along
with the addition of JavaBeans, a component programming model that is oriented
toward the easy creation of visual programming environments. Java 2 finishes the
transformation away from the old Java 1.0 AWT by essentially replacing
everything with the Java
Foundation Classes (JFC), the GUI portion of which is called
“Swing.” These are a rich set of
easy-to-use, easy-to-understand JavaBeans that can be dragged and dropped (as
well as hand programmed) to create a GUI that you can (finally) be satisfied
with. The “revision 3” rule of the software industry (a product
isn’t good until revision 3) seems to hold true with programming languages
as well.
[ Add Comment ]
This chapter does not cover anything but
the modern, Java 2 Swing library, and makes the reasonable assumption that Swing
is the final destination GUI library for Java. If for some reason you need to
use the original “old” AWT (because you’re supporting old code
or you have browser limitations), you can find that introduction in the first
edition of this book, downloadable at www.BruceEckel.com (also included
on the CD ROM bound with this book).
[ Add Comment ]
Early in this chapter, you’ll see
how things are different when you want to create an applet vs. a regular
application using Swing, and how to create programs that are both applets and
applications so they can be run either inside a browser or from the command
line. Almost all the GUI examples in this book will be executable as either
applets or applications.
[ Add Comment ]
Please be aware that this is not a
comprehensive glossary of either all the Swing components, or all the methods
for the described classes. What you see here is intended to be simple. The Swing
library is vast, and the goal of this chapter is only to get you started with
the essentials and comfortable with the concepts. If you need to do more, then
Swing can probably give you what you want if you’re willing to do the
research.
[ Add Comment ]
I assume here that you have downloaded
and installed the (free) Java library documents in HTML format from
java.sun.com and will browse the javax.swing classes in that
documentation to see the full details and methods of the Swing library. Because
of the simplicity of the Swing design, this will often be enough information to
solve your problem. There are numerous (rather thick) books dedicated solely to
Swing and you’ll want to go to those if you need more depth, or if you
want to modify the default Swing behavior.
[ Add Comment ]
As you learn about Swing you’ll
discover:
[ Add Comment ]
Swing
contains all the components that you expect to see in a modern UI, everything
from buttons that contain pictures to trees and tables. It’s a big
library, but it’s designed to have appropriate complexity for the task at
hand—if something is simple, you don’t have to write much code but
as you try to do more complex things, your code becomes proportionally more
complex. This means an easy entry point, but you’ve got the power if you
need it.
[ Add Comment ]
Much of what you’ll like about
Swing could be called “orthogonality of use.” That is, once you pick
up the general ideas about the library you can apply them everywhere. Primarily
because of the standard naming conventions, much of the time that I was writing
these examples I could guess at the method names and get it right the first
time, without looking anything up. This is certainly the hallmark of a good
library design. In addition, you can generally plug components into other
components and things will work correctly.
[ Add Comment ]
For speed, all the
components are “lightweight,” and Swing is
written entirely in Java for portability.
[ Add Comment ]
Keyboard
navigation is automatic—you can run a Swing application without using the
mouse, and this doesn’t require any extra programming. Scrolling support
is effortless—you simply wrap your component in a JScrollPane as
you add it to your form. Features such as tool tips typically require a single
line of code to use.
[ Add Comment ]
Swing also supports a rather radical
feature called “pluggable look and feel,” which means that the
appearance of the UI can be dynamically changed to suit the expectations of
users working under different platforms and operating systems. It’s even
possible (albeit difficult) to invent your own look and feel.
[ Add Comment ]
One of Java’s design goals is to
create applets, which are little programs that run inside a Web browser.
Because they must be safe, applets are limited in what they can accomplish.
However, applets are a powerful tool that support client-side programming, a
major issue for the Web.
[ Add Comment ]
Programming within an applet is so
restrictive that it’s often referred to as being “inside the
sandbox,” since you always have someone—that is, the Java run-time
security system—watching over you.
[ Add Comment ]
However, you can also step outside the
sandbox and write regular applications rather than applets, in which case you
can access the other features of your OS. We’ve been writing regular
applications all along in this book, but they’ve been console
applications without any graphical components. Swing can also be used to
build GUI interfaces for regular applications.
[ Add Comment ]
You can generally answer the question of
what an applet is able to do by looking at what it is supposed to do:
extend the functionality of a Web page in a browser. Since, as a Net surfer, you
never really know if a Web page is from a friendly place or not, you want any
code that it runs to be safe. So the biggest restrictions you’ll notice
are probably:
[ Add Comment ]
If you can live within the restrictions,
applets have definite advantages, especially when building
client/server or other networked applications:
[ Add Comment ]
Because
applets are automatically integrated with HTML, you have a built-in
platform-independent documentation system to support the applet. It’s an
interesting twist, since we’re used to having the documentation part of
the program rather than vice versa.
[ Add Comment ]
Libraries are often grouped according to
their functionality. Some libraries, for example, are used as is, off the shelf.
The standard Java library String and ArrayList classes are
examples of these. Other libraries are designed specifically as building blocks
to create other classes. A certain category of library is the
application framework,
whose goal is to help you build applications by providing a class or set of
classes that produces the basic behavior that you need in every application of a
particular type. Then, to customize the behavior to your own needs, you inherit
from the application class and override the methods of interest. The application
framework’s default control mechanism will call your overridden methods at
the appropriate time. An application framework is a good example of
“separating the things that change from the things that stay the
same,” since it attempts to localize all the unique parts of a program in
the overridden
methods[62].
[ Add Comment ]
Applets are built using an application
framework. You inherit from class JApplet and override the appropriate
methods. There are a few methods that control the creation and execution of an
applet on a Web page:
|
Method |
Operation |
|---|---|
|
init( ) |
Automatically called to perform
first-time initialization of the applet, including component layout.
You’ll always override this method. |
|
start( ) |
Called every time the applet moves into
sight on the Web browser to allow the applet to start up its normal operations
(especially those that are shut off by stop( )). Also called after
init( ). |
|
stop( ) |
Called every time the applet moves out of
sight on the Web browser to allow the applet to shut off expensive operations.
Also called right before destroy( ). |
|
destroy( ) |
Called when the applet is being unloaded
from the page to perform final release of resources when the applet is no longer
used |
With this information you are ready to
create a simple applet:
//: c13:Applet1.java
// Very simple applet.
import javax.swing.*;
import java.awt.*;
public class Applet1 extends JApplet {
public void init() {
getContentPane().add(new JLabel("Applet!"));
}
} ///:~
Note that applets are not required to
have a main( ). That’s all wired into the application
framework; you put any startup code in init( ).
[ Add Comment ]
In this program, the only activity is
putting a text label on the applet, via the
JLabel class (the old AWT appropriated the name
Label as well as other names of components, so you will often see a
leading “J” used with Swing components). The constructor for
this class takes a String and uses it to create the label. In the above
program this label is placed on the form.
[ Add Comment ]
The
init( ) method is responsible for putting all the components on the
form using the add( ) method. You might think that you ought to be
able to simply call add( ) by itself, and in fact that’s the
way it used to be in the old AWT. However, Swing requires you to add all
components to the “content pane” of a form, and so you must call
getContentPane( ) as part of the add( ) process.
[ Add Comment ]
To run this program you must place it
inside a Web page and view that page inside your Java-enabled Web browser. To
place an applet inside a Web
page you put a special tag inside the HTML source for that Web
page[63] to tell
the page how to load and run the applet.
[ Add Comment ]
This process used to be very simple, when
Java itself was simple and everyone was on the same bandwagon and incorporated
the same Java support inside their Web browsers. Then you might have been able
to get away with a very simple bit of HTML inside your Web page, like
this:
<applet code=Applet1 width=100 height=50> </applet>
Then along came the browser and language
wars, and we (programmers and end users alike) lost. After awhile, JavaSoft
realized that we could no longer expect browsers to support the correct flavor
of Java, and the only solution was to provide some kind of add-on that would
conform to a browser’s extension mechanism. By using the extension
mechanism (which a browser vendor cannot disable—in an attempt to gain
competitive advantage—without breaking all the third-party extensions),
JavaSoft guarantees that Java cannot be shut out of the Web browser by an
antagonistic vendor.
[ Add Comment ]
With Internet Explorer, the extension
mechanism is the ActiveX control, and with Netscape it is the plug-in. In your
HTML code, you must provide tags to support both. Here’s what the simplest
resulting HTML page looks like for
Applet1:[64]
//:! c13:Applet1.html
<html><head><title>Applet1</title></head><hr>
<OBJECT
classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
width="100" height="50" align="baseline" codebase="http://java.sun.com/products/plugin/1.2.2/jinstall-1_2_2-win.cab#Version=1,2,2,0">
<PARAM NAME="code" VALUE="Applet1.class">
<PARAM NAME="codebase" VALUE=".">
<PARAM NAME="type" VALUE="application/x-java-applet;version=1.2.2">
<COMMENT>
<EMBED type=
"application/x-java-applet;version=1.2.2"
width="200" height="200" align="baseline"
code="Applet1.class" codebase="."
pluginspage="http://java.sun.com/products/plugin/1.2/plugin-install.html">
<NOEMBED>
</COMMENT>
No Java 2 support for APPLET!!
</NOEMBED>
</EMBED>
</OBJECT>
<hr></body></html>
///:~
Some of these lines were too long and had
to be wrapped to fit on the page. The code in this book’s source code (on
the book’s CD ROM, and downloadable from www.BruceEckel.com) will
work without having to worry about correcting line wraps.
[ Add Comment ]
The code value gives the name of
the .class file where the applet resides. The width and
height specify the initial size of the applet (in pixels, as before).
There are other items you can place within the applet tag: a place to find other
.class files on the Internet
(codebase), alignment
information (align), a
special identifier that makes it possible for applets to communicate with each
other (name), and applet
parameters to provide
information that the applet can retrieve. Parameters are in the
form:
<param name="identifier" value = "information">
and there can be as many as you want.
[ Add Comment ]
The source code package for this book
provides an HTML page for each of the applets in this book, and thus many
examples of the applet tag. You can find a full and current description of the
details of placing applets in Web pages at java.sun.com.
[ Add Comment ]
Sun’s JDK (freely downloadable from
java.sun.com) contains a tool called the
Appletviewer that picks the <applet>
tags out of the HTML file and runs the applets without displaying the
surrounding HTML text. Because the Appletviewer ignores everything but APPLET
tags, you can put those tags in the Java source file as
comments:
// <applet code=MyApplet width=200 height=100> // </applet>
This way, you can run
“appletviewer MyApplet.java” and you don’t need to
create tiny HTML files to run tests. For example, you can add the commented HTML
tags to Applet1.java:
//: c13:Applet1b.java
// Embedding the applet tag for Appletviewer.
// <applet code=Applet1b width=100 height=50>
// </applet>
import javax.swing.*;
import java.awt.*;
public class Applet1b extends JApplet {
public void init() {
getContentPane().add(new JLabel("Applet!"));
}
} ///:~
Now you can invoke the applet with the
command
appletviewer Applet1b.java
In this book, this form will be used for
easy testing of applets. Shortly, you’ll see another coding approach which
will allow you to execute applets from the command line without the
Appletviewer.
[ Add Comment ]
You can perform a simple test without any
network connection by starting up your Web browser and opening the HTML file
containing the applet tag. As the HTML file is loaded, the browser will discover
the applet tag and go hunt for the .class file specified by the
code value. Of course, it looks at the CLASSPATH to find out where to
hunt, and if your .class file isn’t in the CLASSPATH then it will
give an error message on the status line of the browser to the effect that it
couldn’t find that .class file.
[ Add Comment ]
When you want to try this out on your Web
site things are a little more complicated. First of all, you must have a
Web site, which for most people means a third-party
Internet Service Provider (ISP)
at a remote location. Since the applet is just a file or set of files, the ISP
does not have to provide any special support for Java. You must also have a way
to move the HTML files and the .class files from your site to the correct
directory on the ISP machine. This is typically done with a
File Transfer Protocol (FTP)
program, of which there are many different types available for free or as
shareware. So it would seem that all you need to do is move the files to the ISP
machine with FTP, then connect to the site and HTML file using your browser; if
the applet comes up and works, then everything checks out, right?
[ Add Comment ]
Here’s where you can get fooled. If
the browser on the client machine cannot locate the .class file on the
server, it will hunt through the
CLASSPATH on your local
machine. Thus, the applet might not be loading properly from the server, but to
you it looks fine during your testing process because the browser finds it on
your machine. When someone else connects, however, his or her browser
can’t find it. So when you’re testing, make sure you erase the
relevant .class files (or .jar file) on your local machine to
verify that they exist in the proper location on the server.
[ Add Comment ]
One of the most insidious places where
this happened to me is when I innocently placed an applet inside a
package. After uploading the HTML file and applet, it turned out that the
server path to the applet was confused because of the package name. However, my
browser found it in the local CLASSPATH. So I was the only one who could
properly load the applet. It took some time to discover that the package
statement was the culprit. In general, you’ll want to leave the
package statement out of
an applet.
[ Add Comment ]
There are times when you’d like to
make a windowed program do something else other than sit on a Web page. Perhaps
you’d also like it to do some of the things a “regular”
application can do but still have the vaunted instant portability provided by
Java. In previous chapters in this book we’ve made command-line
applications, but in some operating environments (the Macintosh, for example)
there isn’t a command line. So for any number of reasons you’d like
to build a windowed, non-applet program using Java. This is certainly a
reasonable desire.
[ Add Comment ]
The Swing library allows you to make an
application that preserves the look and feel of the underlying operating
environment. If you want to build windowed applications, it makes sense to do
so[65] only if you
can use the latest version of Java and associated tools so you can deliver
applications that won’t confound your users. If for some reason
you’re forced to use an older version of Java, think hard before
committing to building a significant windowed application.
[ Add Comment ]
Often
you’ll want to be able to create a class that can be invoked as either a
window or an applet. This is especially convenient when you’re testing the
applets, since it’s typically much faster and easier to run the resulting
applet-application from the command line than it is to start up a Web browser or
the Appletviewer.
[ Add Comment ]
To create an applet that can be run from
the console command line, you simply add a main( ) to your applet
that builds an instance of the applet inside a
JFrame.[66]
As a simple example, let’s look at Applet1b.java modified to work
as both an application and an applet:
//: c13:Applet1c.java
// An application and an applet.
// <applet code=Applet1c width=100 height=50>
// </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class Applet1c extends JApplet {
public void init() {
getContentPane().add(new JLabel("Applet!"));
}
// A main() for the application:
public static void main(String[] args) {
JApplet applet = new Applet1c();
JFrame frame = new JFrame("Applet1c");
// To close the application:
Console.setupClosing(frame);
frame.getContentPane().add(applet);
frame.setSize(100,50);
applet.init();
applet.start();
frame.setVisible(true);
}
} ///:~
main( ) is the only element
added to the applet, and the rest of the applet is untouched. The applet is
created and added to a JFrame so that it can be displayed.
[ Add Comment ]
The line:
Console.setupClosing(frame);
Causes the window to be properly closed.
Console comes from com.bruceeckel.swing and will be explained a
little later.
[ Add Comment ]
You can see that in main( ),
the applet is explicitly initialized and started since in this case the browser
isn’t available to do it for you. Of course, this doesn’t provide
the full behavior of the browser, which also calls stop( ) and
destroy( ), but for most situations it’s acceptable. If
it’s a problem, you can force the calls
yourself.[67]
[ Add Comment ]
Notice the last line:
frame.setVisible(true);
Without this, you won’t see
anything on the screen.
[ Add Comment ]
Although the code that turns programs
into both applets and applications produces valuable results, if used everywhere
it becomes distracting and wastes paper. Instead, the following display
framework will be used for the Swing examples in the rest of this
book:
//: com:bruceeckel:swing:Console.java
// Tool for running Swing demos from the
// console, both applets and JFrames.
package com.bruceeckel.swing;
import javax.swing.*;
import java.awt.event.*;
public class Console {
// Create a title string from the class name:
public static String title(Object o) {
String t = o.getClass().toString();
// Remove the word "class":
if(t.indexOf("class") != -1)
t = t.substring(6);
return t;
}
public static void setupClosing(JFrame frame) {
// The JDK 1.2 Solution as an
// anonymous inner class:
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
// The improved solution in JDK 1.3:
// frame.setDefaultCloseOperation(
// EXIT_ON_CLOSE);
}
public static void
run(JFrame frame, int width, int height) {
setupClosing(frame);
frame.setSize(width, height);
frame.setVisible(true);
}
public static void
run(JApplet applet, int width, int height) {
JFrame frame = new JFrame(title(applet));
setupClosing(frame);
frame.getContentPane().add(applet);
frame.setSize(width, height);
applet.init();
applet.start();
frame.setVisible(true);
}
public static void
run(JPanel panel, int width, int height) {
JFrame frame = new JFrame(title(panel));
setupClosing(frame);
frame.getContentPane().add(panel);
frame.setSize(width, height);
frame.setVisible(true);
}
} ///:~
This is a tool you may want to use
yourself, so it’s placed in the library
com.bruceeckel.swing. The Console class
consists entirely of static methods. The first is used to extract the
class name (using RTTI) from any object and to remove the word
“class,” which is typically prepended by getClass( ).
This uses the String methods indexOf( ) to determine whether
the word “class” is there, and substring( ) to produce
the new string without “class” or the trailing space. This name is
used to label the window that is displayed by the run( ) methods.
[ Add Comment ]
setupClosing( ) is used to
hide the code that causes a JFrame to exit a program when that
JFrame is closed. The default behavior is to do nothing, so if you
don’t call setupClosing( ) or write the equivalent code for
your JFrame, the application won’t close.
The reason this code is hidden rather than placing it directly in the subsequent
run( ) methods is partly because it allows you to use the method by
itself when what you want to do is more complicated than what run( )
provides. However, it also isolates a change factor: Java 2 has two ways of
causing certain types of windows to close. In JDK 1.2, the solution is to create
a new WindowAdapter class and implement
windowClosing( ), as seen above (the meaning
of this will be fully explained later in this chapter). However, during the
creation of JDK 1.3 the library designers observed that you typically need to
close windows whenever you’re creating a non-applet, and so they added the
setDefaultCloseOperation( ) to JFrame
and JDialog. From the standpoint of writing code, the new method is much
nicer to use but this book was written while there was still no JDK 1.3
implemented on Linux and other platforms, so in the interest of cross-version
portability the change was isolated inside setupClosing( ).
[ Add Comment ]
The run( ) method is
overloaded to work with JApplets, JPanels, and JFrames.
Note that only if it’s a JApplet are init( ) and
start( ) called.
[ Add Comment ]
Now any applet can be run from the
console by creating a main( ) containing a line like
this:
Console.run(new MyClass(), 500, 300);
in which the last two arguments are the
display width and height. Here’s Applet1c.java modified to use
Console:
//: c13:Applet1d.java
// Console runs applets from the command line.
// <applet code=Applet1d width=100 height=50>
// </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class Applet1d extends JApplet {
public void init() {
getContentPane().add(new JLabel("Applet!"));
}
public static void main(String[] args) {
Console.run(new Applet1d(), 100, 50);
}
} ///:~
This allows the elimination of repeated
code while providing the greatest flexibility in running the examples.
[ Add Comment ]
If you’re using Windows, you can
simplify the process of running a command-line Java program by configuring the
Windows Explorer—the file
browser in Windows, not the Internet Explorer—so that you can
simply double-click on a .class file to execute it. There are several
steps in this process.
[ Add Comment ]
First, download and install the
Perl programming language from www.Perl.org.
You’ll find the instructions and language documentation on that site.
[ Add Comment ]
Next, create the following script without
the first and last lines (this script is part of this book’s source-code
package):
//:! c13:RunJava.bat @rem = '--*-Perl-*-- @echo off perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9 goto endofperl @rem '; #!perl $file = $ARGV[0]; $file =~ s/(.*)\..*/\1/; $file =~ s/(.*\\)*(.*)/$+/; ´java $file´; __END__ :endofperl ///:~
Now, open the Windows Explorer, select
“View,” “Folder Options,” then click on the “File
Types” tab. Press the “New Type” button. For
“Description of Type” enter “Java class file.” For
“Associated Extension,” enter “class.” Under
“Actions” press the “New” button. For
“Action” enter “Open,” and for “Application used
to perform action” enter a line like this:
"c:\aaa\Perl\RunJava.bat" "%L"
You must customize the path before
“RunJava.bat” to conform to the location where you placed the batch
file.
[ Add Comment ]
Once you perform this installation, you
may run any Java program by simply double-clicking on the .class file
containing a main( ).
[ Add Comment ]
Making a button is quite simple: you just
call the JButton constructor with the label you want on the button.
You’ll see later that you can do fancier things, like putting graphic
images on buttons.
[ Add Comment ]
Usually you’ll want to create a
field for the button inside your class so that you can refer to it later.
[ Add Comment ]
The JButton is a
component—its own little window—that will automatically get
repainted as part of an update. This means that you don’t explicitly paint
a button or any other kind of control; you simply place them on the form and let
them automatically take care of painting themselves. So to place a button on a
form, you do it inside init( ):
//: c13:Button1.java
// Putting buttons on an applet.
// <applet code=Button1 width=200 height=50>
// </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class Button1 extends JApplet {
JButton
b1 = new JButton("Button 1"),
b2 = new JButton("Button 2");
public void init() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(b1);
cp.add(b2);
}
public static void main(String[] args) {
Console.run(new Button1(), 200, 50);
}
} ///:~
Something new has been added here: before
any elements are placed on the content pane, it is given a new “layout
manager,” of type FlowLayout. The layout manager is the way that
the pane implicitly decides where to place the control on the form. The normal
behavior of an applet is to use the BorderLayout, but that won’t
work here because (as you will learn later in this chapter when controlling the
layout of a form is examined in more detail) it defaults to covering each
control entirely with every new one that is added. However, FlowLayout
causes the controls to flow evenly onto the form, left to right and top to
bottom.
[ Add Comment ]
You’ll notice that if you compile
and run the applet above, nothing happens when you press the buttons. This is
where you must step in and write some code to determine what will happen. The
basis of event-driven
programming, which comprises a lot of what a GUI is about, is tying events to
code that responds to those events.
[ Add Comment ]
The way that this is accomplished in
Swing is by cleanly separating the interface (the graphical components) and the
implementation (the code that you want to run when an event happens to a
component). Each Swing component can report all the events that might happen to
it, and it can report each kind of event individually. So if you’re not
interested in, for example, whether the mouse is being moved over your button,
you don’t register your interest in that event. It’s a very
straightforward and elegant way to handle event-driven programming, and once you
understand the basic concepts you can easily use Swing components that you
haven’t seen before—in fact, this model extends to anything that can
be classified as a JavaBean (which you’ll learn about later in the
chapter).
[ Add Comment ]
At first, we will just focus on the main
event of interest for the components being used. In the case of a
JButton, this “event of interest” is that the button is
pressed. To register your interest in when a button is pressed, you call
the JButton’s addActionListener( ) method. This method
expects an argument that is an object that implements the ActionListener
interface, which contains a single method called actionPerformed( ).
So all you have to do to attach code to a JButton is to implement the
ActionListener interface in a class, and register an object of that class
with the JButton via addActionListener( ). The method will be
called when the button is pressed (this is normally referred to as a
callback).
[ Add Comment ]
But what should the result of pressing
that button be? We’d like to see something change on the screen, so a new
Swing component will be introduced: the
JTextField. This is a place where text can be
typed, or in this case modified by the program. Although there are a number of
ways to create a JTextField, the simplest is just to tell the constructor
how wide you want that field to be. Once the JTextField is placed on the
form, you can modify its contents by using the setText( ) method
(there are many other methods in JTextField, but you must look these up
in the HTML documentation for the JDK from java.sun.com). Here is what it
looks like:
//: c13:Button2.java
// Responding to button presses.
// <applet code=Button2 width=200 height=75>
// </applet>
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class Button2 extends JApplet {
JButton
b1 = new JButton("Button 1"),
b2 = new JButton("Button 2");
JTextField txt = new JTextField(10);
class BL implements ActionListener {
public void actionPerformed(ActionEvent e){
String name =
((JButton)e.getSource()).getText();
txt.setText(name);
}
}
BL al = new BL();
public void init() {
b1.addActionListener(al);
b2.addActionListener(al);
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(b1);
cp.add(b2);
cp.add(txt);
}
public static void main(String[] args) {
Console.run(new Button2(), 200, 75);
}
} ///:~
Creating a JTextField and placing
it on the canvas takes the same steps as for JButtons, or for any Swing
component. The difference in the above program is in the creation of the
aforementioned ActionListener class BL. The argument to
actionPerformed( ) is of type ActionEvent, which contains all
the information about the event and where it came from. In this case, I wanted
to describe the button that was pressed: getSource( ) produces the
object where the event originated, and I assumed that is a JButton.
getText( ) returns the text that’s on the button, and this is
placed in the JTextField to prove that the code was actually called when
the button was pressed.
[ Add Comment ]
In init( ),
addActionListener( ) is used to register the BL object with
both the buttons.
[ Add Comment ]
It is often more convenient to code the
ActionListener as an
anonymous
inner class, especially since you tend to only use a single instance of each
listener class. Button2.java can be modified to use an anonymous inner
class as follows:
[ Add Comment ]
//: c13:Button2b.java
// Using anonymous inner classes.
// <applet code=Button2b width=200 height=75>
// </applet>
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class Button2b extends JApplet {
JButton
b1 = new JButton("Button 1"),
b2 = new JButton("Button 2");
JTextField txt = new JTextField(10);
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e){
String name =
((JButton)e.getSource()).getText();
txt.setText(name);
}
};
public void init() {
b1.addActionListener(al);
b2.addActionListener(al);
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(b1);
cp.add(b2);
cp.add(txt);
}
public static void main(String[] args) {
Console.run(new Button2b(), 200, 75);
}
} ///:~
The approach of using an anonymous inner
class will be preferred (when possible) for the examples in this book.
[ Add Comment ]
A
JTextArea is like a JTextField except that
it can have multiple lines and has more functionality. A particularly useful
method is append( ); with this you can easily pour output into the
JTextArea, thus making a Swing program an improvement (since you can
scroll backward) over what has been accomplished thus far using command-line
programs that print to standard output. As an example, the following program
fills a JTextArea with the output from the geography generator in
Chapter 9:
//: c13:TextArea.java
// Using the JTextArea control.
// <applet code=TextArea width=475 height=425>
// </applet>
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;
import com.bruceeckel.swing.*;
import com.bruceeckel.util.*;
public class TextArea extends JApplet {
JButton
b = new JButton("Add Data"),
c = new JButton("Clear Data");
JTextArea t = new JTextArea(20, 40);
Map m = new HashMap();
public void init() {
// Use up all the data:
Collections2.fill(m,
Collections2.geography,
CountryCapitals.pairs.length);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
for(Iterator it= m.entrySet().iterator();
it.hasNext();){
Map.Entry me = (Map.Entry)(it.next());
t.append(me.getKey() + ": "
+ me.getValue() + "\n");
}
}
});
c.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
t.setText("");
}
});
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(new JScrollPane(t));
cp.add(b);
cp.add(c);
}
public static void main(String[] args) {
Console.run(new TextArea(), 475, 425);
}
} ///:~
In init( ), the Map is
filled with all the countries and their capitals. Note that for both buttons the
ActionListener is created and added without
defining an intermediate variable, since you never need to refer to that
listener again during the program. The “Add Data” button formats and
appends all the data, while the “Clear Data” button uses
setText( ) to remove all the text from the JTextArea.
[ Add Comment ]
As the JTextArea is added to the
applet, it is wrapped in a
JScrollPane, to control
scrolling when too much text is placed on the screen. That’s all you must
do in order to produce full scrolling capabilities. Having tried to figure out
how to do the equivalent in some other GUI programming environments, I am very
impressed with the simplicity and good design of components like
JScrollPane.
[ Add Comment ]
The way that you place components on a
form in Java is probably different from any other GUI system you’ve used.
First, it’s all code; there are no “resources” that control
placement of components. Second, the way components are placed on a form is
controlled not by absolute positioning but by a “layout manager”
that decides how the components lie based on the order that you
add( ) them. The size, shape, and placement of components will be
remarkably different from one layout manager to another. In addition, the layout
managers adapt to the dimensions of your applet or application window, so if the
window dimension is changed, the size, shape, and placement of the components
can change in response.
[ Add Comment ]
JApplet,
JFrame JWindow, and JDialog can all produce a Container
with getContentPane( ) that can contain and display
Components. In Container, there’s a method called
setLayout( ) that allows you to choose a
different layout manager. Other classes, such as
JPanel, contain and display components directly
and so you also set the layout manager directly, without using the content pane.
[ Add Comment ]
In this section we’ll explore the
various layout managers by placing buttons in them (since that’s the
simplest thing to do). There won’t be any capturing of button events since
these examples are just intended to show how the buttons are laid out.
[ Add Comment ]
The applet uses a default layout scheme:
the BorderLayout (a number of the previous
example have changed the layout manager to FlowLayout). Without any other
instruction, this takes whatever you add( ) to it and places it in
the center, stretching the object all the way out to the edges.
[ Add Comment ]
However, there’s more to the
BorderLayout. This layout manager has the concept of four border regions
and a center area. When you add something to a panel that’s using a
BorderLayout you can use the overloaded add( ) method that
takes a constant value as its first argument. This value can be any of the
following:
BorderLayout. NORTH
(top)
BorderLayout. SOUTH
(bottom)
BorderLayout. EAST
(right)
BorderLayout. WEST
(left)
BorderLayout.CENTER (fill the
middle, up to the other components or to the edges)
[ Add Comment ]
If you don’t specify an area to
place the object, it defaults to CENTER.
[ Add Comment ]
Here’s a simple example. The
default layout is used, since JApplet defaults to
BorderLayout:
//: c13:BorderLayout1.java
// Demonstrates BorderLayout.
// <applet code=BorderLayout1
// width=300 height=250> </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class BorderLayout1 extends JApplet {
public void init() {
Container cp = getContentPane();
cp.add(BorderLayout.NORTH,
new JButton("North"));
cp.add(BorderLayout.SOUTH,
new JButton("South"));
cp.add(BorderLayout.EAST,
new JButton("East"));
cp.add(BorderLayout.WEST,
new JButton("West"));
cp.add(BorderLayout.CENTER,
new JButton("Center"));
}
public static void main(String[] args) {
Console.run(new BorderLayout1(), 300, 250);
}
} ///:~
For every placement but CENTER,
the element that you add is compressed to fit in the smallest amount of space
along one dimension while it is stretched to the maximum along the other
dimension. CENTER, however, spreads out in both dimensions to occupy the
middle.
[ Add Comment ]
This simply “flows” the
components onto the form, from left to right until the top space is full, then
moves down a row and continues flowing.
[ Add Comment ]
Here’s an example that sets the
layout manager to FlowLayout and then places buttons on the form.
You’ll notice that with FlowLayout the components take on their
“natural” size. A JButton, for example, will be the size of
its string.
[ Add Comment ]
//: c13:FlowLayout1.java
// Demonstrates FlowLayout.
// <applet code=FlowLayout1
// width=300 height=250> </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class FlowLayout1 extends JApplet {
public void init() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
for(int i = 0; i < 20; i++)
cp.add(new JButton("Button " + i));
}
public static void main(String[] args) {
Console.run(new FlowLayout1(), 300, 250);
}
} ///:~
All components will be compacted to their
smallest size in a FlowLayout, so you might get a little bit of
surprising behavior. For example, because a JLabel will be the size of
its string, attempting to right-justify its text yields an unchanged display
when using FlowLayout.
[ Add Comment ]
A
GridLayout allows you to build a table of
components, and as you add them they are placed left-to-right and top-to-bottom
in the grid. In the constructor you specify the number of rows and columns that
you need and these are laid out in equal proportions.
[ Add Comment ]
//: c13:GridLayout1.java
// Demonstrates GridLayout.
// <applet code=GridLayout1
// width=300 height=250> </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class GridLayout1 extends JApplet {
public void init() {
Container cp = getContentPane();
cp.setLayout(new GridLayout(7,3));
for(int i = 0; i < 20; i++)
cp.add(new JButton("Button " + i));
}
public static void main(String[] args) {
Console.run(new GridLayout1(), 300, 250);
}
} ///:~
In this case there are 21 slots but only
20 buttons. The last slot is left empty because no “balancing” goes
on with a GridLayout.
[ Add Comment ]
The
GridBagLayout provides you with tremendous
control in deciding exactly how the regions of your window will lay themselves
out and reformat themselves when the window is resized. However, it’s also
the most complicated layout manager, and quite difficult to understand. It is
intended primarily for automatic code generation by a GUI builder (good GUI
builders will use GridBagLayout instead of absolute placement). If your
design is so complicated that you feel you need to use GridBagLayout,
then you should be using a GUI builder tool to generate that design. If you feel
you must know the intricate details, I’ll refer you to Core Java 2
by Horstmann & Cornell (Prentice-Hall, 1999), or a dedicated Swing book, as
a starting point.
[ Add Comment ]
Some
GUI builders use this approach extensively, but this is usually not the best way
to generate code. More useful GUI builders will use GridBagLayout
instead.
[ Add Comment ]
Because people had so much trouble
understanding and working with GridBagLayout, Swing also includes the
BoxLayout, which gives you many of the benefits of GridBagLayout
without the complexity, so you can often use it when you need to do hand-coded
layouts (again, if your design becomes too complex, use a GUI builder that
generates GridBagLayouts for you). BoxLayout allows you to control
the placement of components either vertically or horizontally, and to control
the space between the components using something called
“struts and glue.”
First, let’s see how to use the BoxLayout directly, in the same way
that the other layout managers have been demonstrated:
//: c13:BoxLayout1.java
// Vertical and horizontal BoxLayouts.
// <applet code=BoxLayout1
// width=450 height=200> </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class BoxLayout1 extends JApplet {
public void init() {
JPanel jpv = new JPanel();
jpv.setLayout(
new BoxLayout(jpv, BoxLayout.Y_AXIS));
for(int i = 0; i < 5; i++)
jpv.add(new JButton("" + i));
JPanel jph = new JPanel();
jph.setLayout(
new BoxLayout(jph, BoxLayout.X_AXIS));
for(int i = 0; i < 5; i++)
jph.add(new JButton("" + i));
Container cp = getContentPane();
cp.add(BorderLayout.EAST, jpv);
cp.add(BorderLayout.SOUTH, jph);
}
public static void main(String[] args) {
Console.run(new BoxLayout1(), 450, 200);
}
} ///:~
The constructor for BoxLayout is a
bit different than the other layout managers—you provide the
Container that is to be controlled by the BoxLayout as the first
argument, and the direction of the layout as the second argument.
[ Add Comment ]
To simplify matters, there’s a
special container called Box that uses
BoxLayout as its native manager. The following example lays out
components horizontally and vertically using Box, which has two
static methods to create boxes with vertical and horizontal
alignment:
//: c13:Box1.java
// Vertical and horizontal BoxLayouts.
// <applet code=Box1
// width=450 height=200> </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class Box1 extends JApplet {
public void init() {
Box bv = Box.createVerticalBox();
for(int i = 0; i < 5; i++)
bv.add(new JButton("" + i));
Box bh = Box.createHorizontalBox();
for(int i = 0; i < 5; i++)
bh.add(new JButton("" + i));
Container cp = getContentPane();
cp.add(BorderLayout.EAST, bv);
cp.add(BorderLayout.SOUTH, bh);
}
public static void main(String[] args) {
Console.run(new Box1(), 450, 200);
}
} ///:~
Once you have a Box, you pass it
as a second argument when adding components to the content pane.
[ Add Comment ]
Struts add space between components,
measured in pixels. To use a strut, you simply add it in between the addition of
the components that you want spaced apart:
//: c13:Box2.java
// Adding struts.
// <applet code=Box2
// width=450 height=300> </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class Box2 extends JApplet {
public void init() {
Box bv = Box.createVerticalBox();
for(int i = 0; i < 5; i++) {
bv.add(new JButton("" + i));
bv.add(Box.createVerticalStrut(i*10));
}
Box bh = Box.createHorizontalBox();
for(int i = 0; i < 5; i++) {
bh.add(new JButton("" + i));
bh.add(Box.createHorizontalStrut(i*10));
}
Container cp = getContentPane();
cp.add(BorderLayout.EAST, bv);
cp.add(BorderLayout.SOUTH, bh);
}
public static void main(String[] args) {
Console.run(new Box2(), 450, 300);
}
} ///:~
Struts separate components by a fixed
amount, but glue is the opposite: it separates components by as much as
possible. Thus it’s more of a “spring” than “glue”
(and the design on which this was based was called “springs and
struts” so the choice of the term is a bit mysterious).
[ Add Comment ]
//: c13:Box3.java
// Using Glue.
// <applet code=Box3
// width=450 height=300> </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class Box3 extends JApplet {
public void init() {
Box bv = Box.createVerticalBox();
bv.add(new JLabel("Hello"));
bv.add(Box.createVerticalGlue());
bv.add(new JLabel("Applet"));
bv.add(Box.createVerticalGlue());
bv.add(new JLabel("World"));
Box bh = Box.createHorizontalBox();
bh.add(new JLabel("Hello"));
bh.add(Box.createHorizontalGlue());
bh.add(new JLabel("Applet"));
bh.add(Box.createHorizontalGlue());
bh.add(new JLabel("World"));
bv.add(Box.createVerticalGlue());
bv.add(bh);
bv.add(Box.createVerticalGlue());
getContentPane().add(bv);
}
public static void main(String[] args) {
Console.run(new Box3(), 450, 300);
}
} ///:~
A strut works in one direction, but a
rigid area fixes the spacing between components in both
directions:
//: c13:Box4.java
// Rigid Areas are like pairs of struts.
// <applet code=Box4
// width=450 height=300> </applet>
import javax.swing.*;
import java.awt.*;
import com.bruceeckel.swing.*;
public class Box4 extends JApplet {
public void init() {
Box bv = Box.createVerticalBox();
bv.add(new JButton("Top"));
bv.add(Box.createRigidArea(
new Dimension(120, 90)));
bv.add(new JButton("Bottom"));
Box bh = Box.createHorizontalBox();
bh.add(new JButton("Left"));
bh.add(Box.createRigidArea(
new Dimension(160, 80)));
bh.add(new JButton("Right"));
bv.add(bh);
getContentPane().add(bv);
}
public static void main(String[] args) {
Console.run(new Box4(), 450, 300);
}
} ///:~
You should be aware that rigid areas are
a bit controversial. Since they use absolute values, some people feel that they
cause more trouble than they are worth.
[ Add Comment ]
Swing is powerful; it can get a lot done
with a few lines of code. The examples shown in this book are reasonably simple,
and for learning purposes it makes sense to write them by hand. You can actually
accomplish quite a bit by combining simple layouts. At some point, however, it
stops making sense to hand-code GUI forms—it becomes too complicated and
is not a good use of your programming time. The Java and Swing designers
oriented the language and libraries to support GUI building tools, which have
been created for the express purpose of making your programming experience
easier. As long as you understand what’s going on with layouts and how to
deal with the events (described next), it’s not particularly important
that you actually know the details of how to lay out components by
hand—let the appropriate tool do that for you (Java is, after all,
designed to increase programmer productivity).
[ Add Comment ]
In the Swing event model a component can
initiate (“fire”) an event. Each type of event is represented by a
distinct class. When an event is fired, it is received by one or more
“listeners,” which act on that event. Thus, the source of an event
and the place where the event is handled can be separate. Since you typically
use Swing components as they are, but need to write code that is called when the
components receive an event, this is an excellent example of the separation of
interface and implementation.
[ Add Comment ]
Each
event listener is an object of a class that implements a particular type of
listener interface. So as a programmer, all you do is create a listener
object and register it with the component that’s firing the event. This
registration is performed by calling an addXXXListener( ) method in
the event-firing component, in which “XXX” represents the
type of event listened for. You can easily know what types of events can be
handled by noticing the names of the “addListener” methods, and if
you try to listen for the wrong events you’ll discover your mistake at
compile-time. You’ll see later in the chapter that JavaBeans also use the
names of the “addListener” methods to determine what events a Bean
can handle.
[ Add Comment ]
All of your event logic, then, will go
inside a listener class. When you create a listener class, the sole restriction
is that it must implement the appropriate interface. You can create a global
listener class, but this is a situation in which
inner classes tend to be quite
useful, not only because they provide a logical grouping of your listener
classes inside the UI or business logic classes they are serving, but because
(as you shall see later) the fact that an inner class object keeps a reference
to its parent object provides a nice way to call across class and subsystem
boundaries.
[ Add Comment ]
All the examples so far in this chapter
have been using the Swing event model, but the remainder of this section will
fill out the details of that model.
[ Add Comment ]
All Swing components include
addXXXListener( ) and removeXXXListener( ) methods so
that the appropriate types of listeners can be added and removed from each
component. You’ll notice that the “XXX” in each case
also represents the argument for the method, for example:
addMyListener(MyListener m). The following table includes the basic
associated events, listeners, and methods, along with the basic components that
support those particular events by providing the
addXXXListener( ) and
removeXXXListener( ) methods. You should
keep in mind that the event model is designed to be extensible, so you may
encounter other events and
listener types that are not covered in this table.
|
Event, listener interface and add- and
remove-methods |
Components supporting this
event |
|---|---|
|
ActionEvent |
JButton, JList, JTextField, JMenuItem
and its derivatives including JCheckBoxMenuItem, JMenu, and
JpopupMenu. |
|
AdjustmentEvent |
JScrollbar |
|
ComponentEvent |
*Component and its derivatives,
including JButton, JCanvas, JCheckBox, JComboBox, Container, JPanel, JApplet,
JScrollPane, Window, JDialog, JFileDialog, JFrame, JLabel, JList, JScrollbar,
JTextArea, and JTextField. |
|
ContainerEvent |
Container and its derivatives,
including JPanel, JApplet, JScrollPane, Window, JDialog, JFileDialog,
and JFrame. |
|
FocusEvent |
Component and
derivatives*. |
|
KeyEvent |
Component and
derivatives*. |
|
MouseEvent (for both clicks and
motion) |
Component and derivatives*.
|
|
MouseEvent[68]
(for both clicks and
motion) |
Component and
derivatives*. |
|
WindowEvent |
Window and its derivatives,
including JDialog, JFileDialog, and JFrame. |
|
ItemEvent |
JCheckBox, JCheckBoxMenuItem,
JComboBox, JList, and anything that implements the ItemSelectable
interface. |
|
TextEvent |
Anything derived from JTextComponent,
including JTextArea and JTextField. |
You can see that each type of component
supports only certain types of events. It turns out to be rather difficult to
look up all the events supported by each component. A simpler approach is to
modify the ShowMethodsClean.java program from Chapter 12 so that it
displays all the event listeners supported by any Swing component that you
enter.
Chapter 12
introduced reflection and used that feature to
look up methods for a particular class—either the entire list of methods
or a subset of those whose names match a keyword that you provide. The magic of
this is that it can automatically show you all the methods for a class
without forcing you to walk up the inheritance hierarchy examining the base
classes at each level. Thus, it provides a valuable timesaving tool for
programming: because the names of most Java methods are made nicely verbose and
descriptive, you can search for the method names that contain a particular word
of interest. When you find what you think you’re looking for, check the
online documentation.
[ Add Comment ]
However, by Chapter 12 you hadn’t
seen Swing, so the tool in that chapter was developed as a command-line
application. Here is the more useful GUI version, specialized to look for the
“addListener” methods in Swing components:
//: c13:ShowAddListeners.java
// Display the "addXXXListener" methods of any
// Swing class.
// <applet code = ShowAddListeners
// width=500 height=400></applet>
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.*;
import java.io.*;
import com.bruceeckel.swing.*;
import com.bruceeckel.util.*;
public class ShowAddListeners extends JApplet {
Class cl;
Method[] m;
Constructor[] ctor;
String[] n = new String[0];
JTextField name = new JTextField(25);
JTextArea results = new JTextArea(40, 65);
class NameL implements ActionListener {
public void actionPerformed(ActionEvent e) {
String nm = name.getText().trim();
if(nm.length() == 0) {
results.setText("No match");
n = new String[0];
return;
}
try {
cl = Class.forName("javax.swing." + nm);
} catch(ClassNotFoundException ex) {
results.setText("No match");
return;
}
m = cl.getMethods();
// Convert to an array of Strings:
n = new String[m.length];
for(int i = 0; i < m.length; i++)
n[i] = m[i].toString();
reDisplay();
}
}
void reDisplay() {
// Create the result set:
String[] rs = new String[n.length];
int j = 0;
for (int i = 0; i < n.length; i++)
if(n[i].indexOf("add") != -1 &&
n[i].indexOf("Listener") != -1)
rs[j++] =
n[i].substring(n[i].indexOf("add"));
results.setText("");
for (int i = 0; i < j; i++)
results.append(
StripQualifiers.strip(rs[i]) + "\n");
}
public void init() {
name.addActionListener(new NameL());
JPanel top = new JPanel();
top.add(new JLabel(
"Swing class name (press ENTER):"));
top.add(name);
Container cp = getContentPane();
cp.add(BorderLayout.NORTH, top);
cp.add(new JScrollPane(results));
}
public static void main(String[] args) {
Console.run(new ShowAddListeners(), 500,400);
}
} ///:~
The StripQualifiers class defined
in Chapter 12 is reused here by importing the com.bruceeckel.util
library.
[ Add Comment ]
The GUI contains a JTextField
name in which you can enter the Swing class name you want to look up. The
results are displayed in a JTextArea.
[ Add Comment ]
You’ll notice that there are no
buttons or other components by which to indicate that you want the search to
begin. That’s because the JTextField is monitored by an
ActionListener. Whenever you make a change and press ENTER, the list is
immediately updated. If the text isn’t empty, it is used inside
Class.forName( ) to
try to look up the class. If the name is incorrect, Class.forName( )
will fail, which means that it throws an exception. This is trapped and the
JTextArea is set to “No match.” But if you type in a correct
name (capitalization counts), Class.forName( ) is successful and
getMethods( ) will return an array of Method objects. Each of
the objects in the array is turned into a String via
toString( ) (this produces the complete method signature) and added
to n, a String array. The array n is a member of class
ShowAddListeners and is used in updating the display whenever
reDisplay( ) is called.
[ Add Comment ]
reDisplay( ) creates an array
of String called rs (for “result set”). The result set
is conditionally copied from the Strings in n that contain
“add” and “Listener.” indexOf( ) and
substring( ) are then used to remove the qualifiers like
public, static, etc. Finally, StripQualifiers.strip( )
removes the extra name qualifiers.
[ Add Comment ]
This program is a convenient way to
investigate the capabilities of a Swing component. Once you know which events a
particular component supports, you don’t need to look anything up to react
to that event. You simply: