Java Abstract Window Toolkit
Glenn D. Blank
(http://www.eecs.lehigh.edu/~glennb/oose/java/javaawt.htm)
These notes assume my Java lecture notes as background. (Those notes also contain explain the JDK and JavaEdit.)
Most GUI class libraries in C++ are platform specific, not just because of
different hardware capabilities,
but subtle differences between the "look-and-feel"
of various Windowing operating systems.
The Java Abstract Window Toolkit provides a cross-platform library
which seeks to observe look-and-feel
conventions of various OS platforms.
Toolkit --------------------------------------------------------- AWT
--------|---------
Button
List
JVM
------|-------------|-------------------------------------------------------------------
Button Peer List
Peer
Native GUI (Windows, Mac, X)
The AWT uses a "common functionality/specific implementation"
approach
AWT GUI classes are platform-independent elements
Each AWT platform-specific toolkit comes with peer class for
each platform-independent class
which implements the
platform-specific behavior of the AWT class
Thus, combining the platform-independent class with its
platform-specific peer
transforms generic, abstract windows
behavior into specific, particular behavior.
That's the general idea...
The JDK invokes peer classes, such as ButtonPeer, at
runtime:
class TestPeer
{ Frame myFrame = new Frame("my Frame"); //create window
Frame
Button myButton = new Button("my Button");
//create myButton
myFrame.add("Center",myButton); //put
myButton in myFrame
myFrame.setVisible(true); //button appears in window on
screen
//setVisible() creates peer objects for myFrame &
myButton
ComponentPeer buttonPeer = myButton.getPeer(); //now works
}
Peer classes are usually hidden from developers--why?
In fact, in newer versions of JDK,
getPeer() method is now "deprecated"
I.e., peer classes are strongly
discouraged for code maintenance purposes
JDK 1.0 went a long way to implementing these ideas, but (as Bruce Eckel
puts it)
"produced a GUI that looks equally mediocre on all
systems." Just 4 fonts; can’t access GUI of native OS.
JDK 1.1 makes AWT more robust and extensible (i.e., more object-oriented), and
supports Java Beans.
New delegation-based event model more neatly
separates user interface from problem domain classes:
Instead of non-object-oriented cascaded if
statements testing for object type that typified logic using old AWT,
new AWT designates objects as
"listeners" of events triggered by objects modeling the problem
domain.
Other enhancements: cut/paste to the clipboard,
popup menus, printing, mouseless operation, etc.
JDK 1.2 adds Java Foundation Classes, the GUI portion of which is Swing.
Much richer class library plus better integration
with look and feel of GUI of OS.
Eckel comments: "The ‘revision 3’ rule of
software industry (a product isn’t good until revision 3) seems to hold true
with programming languages as well."
There's lots of documentation about the JDK online!
AWT class hierarchy
AWT is a hierarchy of classes in the JDK. Here's a snippet from the AWT hierarchy:
Object
^
Graphics
CheckboxGroup
Color
Component
^ Button
Checkbox
Choice
Container
^ Window
^ Frame
Label
Panel
TextComponent
^ TextArea
^ TextField
FlowLayout
BorderLayout
...
Component contributes several useful public methods to all its subclasses:
public void setSize(int
width, int height); //set in pixels
public void setBackground(Color
c); //see class Color for
colors
public void setVisible(boolean
b); //cause it display on
screen
Container is an abstract
class:
I.e., it cannot be instantiated; some of its methods must be
implemented by subclasses.
Nevertheless, Container does implement some useful methods,
including:
public Component add(Component comp); //put a Component into a Container
public setLayout(LayoutManager mgr); //lay out components in some pattern
A Window
object is a top-level window with no borders and no menubar.
It can generate a WindowOpened or a WindowClosed
event,
to which a WindowListener or WindowAdapter can respond. (We'll
discuss events further below.)
A Frame
is a top-level window with a title and a border.
Because it has more features, it can generate more events: WindowOpened, WindowClosing, WindowClosed,
WindowIconified, WindowDeiconified,
WindowActivated,
WindowDeactivated.
Again, respond to these events with
a WindowListener
or WindowAdapter.
Once a subclass of Container,
such as Window
or Frame
or Panel,
has been constructed,
it can then invoke an add method to attach any AWT component
within it,
such as a Button or a Label or a TextField or another Frame or Panel.
A simple example
Here's a simple program (Ex_1.java) which constructs a Frame and an unresponsive Button:
//program to demonstrate the construction of a Container and a Button
import java.awt.*;
class
Gui extends Frame
{
// constructor
public Gui(String s)
{ super(s); //construct Frame part of Gui
setBackground(Color.yellow);
setLayout(new FlowLayout());
Button pushButton = new Button("press me");
add(pushButton);
}
}
//class Gui
class Ex_1
{
public static void main(String[] args)
{ Gui screen = new Gui("Example 1");
screen.setSize(500,100);
screen.setVisible(true);
}
} //class Ex_1
What do you think this program does? What doesn't it do?
Responding to events
The next example (Ex_3.java)
adds the ability to responds to events, such as a mouse button click
Uses the event delegation model of
JDK 1.1
When an event occurs, when a Button
is pressed, an ActionEvent
objects is generated
The ActionListener interface listens for a
particular ActionEvent
and responds in its actionPerformed
method
The WindowListener interface listens for
events associated with Window objects,
such as
closing a window, and responds in corresponding methods
//Program to demonstrate action listeners and event handlers
import java.awt.*;
import java.awt.event.*;
class Gui extends Frame implements ActionListener, WindowListener
{
//constructor
public Gui(String s)
{ super(s);
setBackground(Color.yellow);
setLayout(new FlowLayout());
addWindowListener(this);
//listen for events on this Window
Button pushButton = new Button("press me");
add(pushButton);
pushButton.addActionListener(this); //listen for Button press
}
//define action for Button press
public void actionPerformed(ActionEvent event)
{ final
char bell = '\u0007';
if (event.getActionCommand().equals("press me"))
{ System.out.print(bell);}
}
//define methods in WindowListener interface
public void windowClosing(WindowEvent event) { System.exit(0); }
public void windowClosed(WindowEvent event) {} //do nothing for now
public void windowDeiconified(WindowEvent event){}
public void windowIconified(WindowEvent event){}
public void windowActivated(WindowEvent event){}
public void windowDeactivated(WindowEvent event){}
public void windowOpened(WindowEvent event){}
}
class Ex_3
{
public static void main(String[] args)
{ Gui
screen = new Gui("Example 3");
screen.setSize(500,100);
screen.setVisible(true);
}
}
The program now has a live
button, whose actionPerformed
method rings a bell,
as
well as a live close window button, which performs System.exit(0)
There are listeners associated with
most Components
in the AWT.
Note: if you implement WindowListener
interface, you have to define all of the methods in it.
Alternatively, the abstract class WindowAdapter defines null methods for them all,
so you can
only have to define methods for events you care about, such as windowClosing.
Sketchpad example
Let's jump into the code for the Sketchpad example (Sketchpad.java):
Layout Managers
Sketchpad uses hard-coded layout, which depends on a 800x600 screen
JDK also provides a set of generic layout
manager classes
which
arrange Component objects within a Container object in various predictable ways
setLayout(new FlowLayout(FlowLayout.LEFT,10,10);
//align LEFT-justify, with 10 vertical & 10 horizontal pixels between
components
for (int counter=1; counter <= 6; counter++)
add(new
Button(String.valueOf(counter)));
1 2 3
4 5 6
setLayout(new GridLayout(3,2,5,5); //3 rows, 2 columns, 5 pixel gaps
//align LEFT-justify, with 10 vertical & 10 horizontal pixels between
components
for (int counter=1; counter <= 6; counter++)
add(new
Button(String.valueOf(counter)));
1 2
3 4
5 6
Applets
So far, these notes have looked at stand-alone applications using Java AWT
On the web, Java programs are called Applets
class java.applet
is a subclass of Panel,
designed to run within a Web browser
For security reasons, Applets are forbidden many
of the capabilities of applications,
such as any
file access, whether read, write or executing programs on a disk,
or network
socket connections anywhere but the server of the applet
Nevertheless, applets have a fair amount of capability,
since they are written in a general purpose programming language
Of course, Web browsers read HTML, so to run an applet, you create HTML code which specifies an applet:
<HTML
<BODY
<APPLET code="HelloWorld.class" width=600 height=300)
</APPLET
</BODY
</HTML
HelloWorld.class
is the Java byte code compiled from the source program HelloWorld.java
the paint() method displays information in
an applet's window (note that this is no main() method)
its parameter, Graphics g, makes
graphics capability available to an applet.
Since class java.applet
inherits from Panel and Container, it has all the capabilities of the AWT.
RadioButtons.java illustrates radio buttons and font control in an applet (run in browser).
Class java.applet also has a number of methods available for manipulating it size, web links and media content.
netlinks.java
illustrates links to other web sites (run in browser)
uses java.net package
to connect to and communicate with other sites on the Internet
1) This program sets up arrays of web site names and corresponding URLs
2) Next, it creates an array of Buttons, each with the name of a web site
3) Method actionPerformed
responds to a Button by getting the corresponding URL
getAppletConext().showDocument(site);
//retrieves page at a URL site
LoadImageAndScale.java illustrates displaying GIF
images in an applet (run this program in
browser)
uses Applet.getImage()
method to retreive an image from a web site
also illustrates
re-scaling the image
Could also load
JPG images
LoadAudioAndPlay.java illustrates playing sounds in
an applet (run this program in browser)
uses class AudioClip, which
is part of the Applet
package, to declare a variable sound:
AudioClip
sound;
uses Applet method getAudioClip to
load a sound from a web page:
sound = getAudioClip(getCodeBase(),"audio\\"+source.toString()+".au");
uses getCodebase() to
return the URL from which the applet's code was loaded
and finally plays
the AudioClip:
sound.play();
Until recently,
the JDK only supported the .au
format,
but support for wav and aiff and midi is coming with JavaSound in
the Java Media Framework.
DeitelLoop.java illustrates
animation of GIF files in an applet (run this program
in browser)
This version
simply loads a set of graphics into an array, then displays them in order.
DeitelLoop5.java
illustrates techniques to improve the performance of animation in an applet
(run this program in browser)
This version
lets you test the effect of changing the sleep time between displaying each
image
(by changing a HTML parameter -- try running with
different parameters)
class MediaTracker determines
when an image is completely loaded,
until tracker.imageImage()
has loaded image before playing it in animation.
This version
also uses double-buffering, i.e., drawing to memory off screen to avoid
flicker:
see buffer
and gContext.
And this
version also uses threads (by implementing the Runnable interface), to permit a user
to stop the animation by leaving the page.
For more working example Java code, you can download the
code from the Deitel & Deitel site
(the same code
that is in Java: How to Program)
or the code from the
Bruce Eckel site (the code that is in Thinking in Java)
Good and bad programming practices
with AWT
Separate user interface logic from "business logic," i.e., the
problem that you are trying to model.
AWT 1.1 "listeners" were designed for this
purpose; inner classes facilitate it further
Separation.java
example illustrates this approach:
class
BusinessLogic
knows nothing about UI;
class
Separation
keeps track of all UI details and talks to BusinessLogic
through its public interface.
How does this design loosely coupled?
How does it support reuse?
How does it support legacy code?
Also note use of inner classes for all "listeners" nested within Separation
Contrast code of badidea1.java:
look at code in actionPerformed
:
public void actionPerformed(ActionEvent e)
{ Object source = e.getSource();
if(source == b1)
System.out.println("Button 1
pressed");
else if(source == b2) System.out.println("Button 2
pressed");
else System.out.println("Something else");
}
badidea2.java improves on things by using adapters,
but still has non-object-oriented code.
Inner classes help to avoid this code.
Why is the cascaded if
above a bad idea?
(Apparently many textbooks encourage this ugly
practice, probably betraying influence of AWT 1.0?)
Suggestion: to eliminate flicker, you may want to override update()
:
public
void update(Graphics g) { paint(g); }
Overrides default version of update()
which clears the background,
then calls paint()
to redraw any graphics
Introduction to Swing
Swing appeared after JDK 1.1, but it’s designed to work with JDK 1.1 as an
add-on; it comes with JDK 1.2.
Sun has an
on-line tutorial. Swing includes lots of features that users have to expect
from a GUI:
In C:\java\jdk1.2\demo\jfc\SwingSet, run java SwingSet
Much JDK 1.1 code is easily ported to Swing: simply add a prefix
"J" to the classes: e.g., JButton
for Button
.
However, Swing adds a number of new types of buttons and changes the way they
are organized:
All buttons, checkboxes, radio buttons and even menu items are inherited from AbstractButton
.
See SwingSet demo’s ButtonPanel.java.
SwingSet swing
(which extends JPanel
)
Jbutton
button
with a label, mnemnonic and a ToolTipTextSee Bruce Eckel’s Buttons.java example:
See Faces example: illustrate including ImageIcons in Jbuttons