Java's Abstract Windowing Toolkit (AWT) provides support for programs
that use Graphical User Interfaces (GUIs), rather than simply communicating
with the user via the keyboard or via files.
The AWT includes classes for commonly used objects like windows, labels,
buttons, and checkboxes.
For more in-depth coverage of the AWT, see chapter 13 of
Java Programming.
Here is a new version of the "Hello World" program.
Rather than writing to the screen, this version
opens a new window and displays "Hello World!" in that window.
Things to note:
Modify the HelloWorld program in each of the following ways:
Below is another version of the HelloWorld program (called Hello1) that
demonstrates more of the power of the AWT.
This program creates a Frame with two sub-components:
When you write a Graphical User Interface, you usually want your program
to respond to user actions, like pushing a button or typing in text.
The mechanism that the Java AWT provides to support this is the creation of
Listeners, which have methods that are invoked in response to
user actions.
Each component can have an associated Listener of the appropriate type
that will respond to user actions involving that component.
There are 3 main kinds of Listeners:
These Listeners are all interfaces (defined in
java.awt.event).
To create your own Listener, you must define a class that implements
one of these interfaces.
For example, in the Hello1 program, the line:
Each kind of Listener has a method (which you must define) that is called
when a particular user action is performed on a component associated with that
Listener:
The components that can have associated Listeners all have methods called
addXXXListener, where XXX is the kind of Listener (Action, Item,
or Text).
To associate a Listener with a component, call the component's
addXXXListener method with the Listener object as the argument.
For example, the call:
Modify the Hello1 program so that the Frame contains two components:
Below is a more complicated example program.
This program creates a Frame with three sub-components:
Selecting one of the List items (by clicking on it with the mouse)
causes the text in the Label to change to the corresponding font.
Clicking on the "reset font" button causes the text to change back to
plain font.
Clicking on the "exit" button terminates the program.
This example uses more components, uses Listeners more extensively,
and also introduces layouts, discussed below. First, though,
consider the following issue, brought up by this example:
If you have several components of the same type (e.g., several Buttons)
and you want to respond to user actions involving each of those components,
you have two choices:
Frames and Panels are both subclasses of the
Container class.
These classes can contain sub-components (like Buttons, Lists,
and Panels), and they have associated layout mechanisms
(schemes for organizing their sub-components).
There are 5 kinds of layouts (only the first 3 will be discussed here):
A container that uses the Flow Layout can contain any number of sub-components.
They are organized in rows across the container.
If there is not enough room for all of the sub-components in a single row,
then a second row is started, etc.
Whether the items in an incomplete row are left-justified, right-justified,
or centered can be specified when the Flow Layout is selected (see below).
The Flow Layout is the default layout for Panels.
The sub-components in a Grid Layout are organized into an N-by-M grid,
where N and M are specified when the Grid Layout is selected.
When a component is added to a container using the Grid Layout, it goes
into the next column of the current row (or the first column of the next
row if the current row is full);
it is not possible to leave empty spaces or to add components out of order.
A particular layout is selected for a container using the container's
setLayout method.
The argument to setLayout is a LayoutManager object.
For example, the statement:
Modify the ChangeFont program in each of the following ways:
Run the two versions of ChangeFont, and compare what happens when you
resize the newly created window.
Java.awt also provides support for simple graphics.
In particular, every component has a paint method, which is
called to display the component on the screen.
It is possible to redefine the paint method for any class that extends
a component class.
For example, here is a program that defines the class Draw
as a subclass of Frame, and redefines the paint method to
draw a stick figure:
Hello World Example
import java.awt.*;
public class HelloWorld extends Frame {
private Label text;
// constructor
public HelloWorld() {
// create a label containing "Hello World!", with the text centered
text = new Label("Hello World!", Label.CENTER);
// add the label to the Frame
add(text);
// set the size of the frame and make it visible
setSize( 300, 100 );
setVisible( true );
}
// main
public static void main( String[] args ) {
new HelloWorld();
}
}
java HelloWorld fishsticks
then the new window contains the text "fishsticks", instead of
"Hello World!".
Example Using Listeners
import java.awt.*;
import java.awt.event.*;
public class Hello1 extends Frame {
private Label text;
private Button exitButton;
// constructor
public Hello1() {
// create a label containing "Hello World!", with the text centered
// and add the label to the top of the Frame
text = new Label("Hello World!", Label.CENTER);
add(text, "North");
// create the exit button and add it to the bottom of the Frame
exitButton = new Button("exit");
add(exitButton, "South");
// create a listener for the exit button that will cause a
// reaction when the button is clicked (using the mouse), and
// associate that listener with the exit button
ExitButtonListener exitListener = new ExitButtonListener();
exitButton.addActionListener(exitListener);
// set the size of the frame and make it visible
setSize( 300, 100 );
setVisible( true );
}
// define the listener for the exit button
class ExitButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// this method will be called when the exit button is clicked;
// end execution of this program
System.exit(0);
}
}
// main
public static void main( String[] args ) {
new Hello1();
}
}
This example introduces the concept of a listener, discussed below.
Listeners
class ExitButtonListener implements ActionListener {
starts the definition of class ExitButtonListener, which is an implementation
of the ActionListener interface.
exitButton.addActionListener(exitListener);
associates the ActionListener named exitListener with the Button object
named exitButton.
Example Using Layout
import java.awt.*;
import java.awt.event.*;
public class ChangeFont extends Frame {
private Font plainFont, boldFont, italicFont, boldItalicFont;
private List fontList;
private Panel buttonPanel;
private Button resetButton, exitButton;
private Label msgLabel;
// constructor
public ChangeFont() {
// create the actual fonts to be used
plainFont = new Font("plain", Font.PLAIN, 10);
boldFont = new Font("bold", Font.BOLD, 10);
italicFont = new Font("italic", Font.ITALIC, 10);
boldItalicFont = new Font("bolditalic", Font.BOLD + Font.ITALIC, 10);
// create the Label whose font will change and add it at the
// top of the Frame
msgLabel = new Label("This text will change font");
msgLabel.setFont(plainFont);
add(msgLabel, "North");
// create the List of fonts and add it in the middle of the Frame
fontList = new List();
fontList.add("bold");
fontList.add("italic");
fontList.add("bold italic");
add(fontList, "Center");
// create the reset and exit buttons
resetButton = new Button("reset font");
exitButton = new Button("exit");
// create a panel to hold the two buttons;
// put the buttons on the panel and add the panel to the bottom of
// the Frame
buttonPanel = new Panel();
buttonPanel.setLayout(new GridLayout(1,2));
buttonPanel.add(resetButton);
buttonPanel.add(exitButton);
add(buttonPanel, "South");
// create listeners for the list of fonts and for the two buttons
ResetButtonListener resetListener = new ResetButtonListener();
ExitButtonListener exitListener = new ExitButtonListener();
ListItemListener listListener = new ListItemListener();
// use the addXXXListener methods of the font list and the buttons
// to associate each listener with the appropriate object
resetButton.addActionListener(resetListener);
exitButton.addActionListener(exitListener);
fontList.addItemListener(listListener);
// arrange the components in the Frame and make it visible
pack();
setVisible(true);
}
class ResetButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// this method will be called when the reset button is clicked;
// change the font back to plain
msgLabel.setFont(plainFont);
}
}
class ExitButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// this method will be called when the exit button is clicked;
// end execution of this program
System.exit(0);
}
}
class ListItemListener implements ItemListener {
public void itemStateChanged(ItemEvent e) {
// this method will be called when one item on the list is
// selected using the mouse;
// get the selected list item and set the label's font accordingly
String S = fontList.getSelectedItem();
if (S.equals("bold")) {
msgLabel.setFont(boldFont);
}
else if (S.equals("italic")) {
msgLabel.setFont(italicFont);
}
else if (S.equals("bold italic")) {
msgLabel.setFont(boldItalicFont);
}
}
}
public static void main(String [] args) {
new ChangeFont();
}
}
class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
// determine which button was clicked and do the right thing
Object source = e.getSource();
if (source == resetButton) msgLabel.setFont(plainFont);
else System.exit(0);
}
}
Layouts
A container that uses the Border Layout can contain up to 5 sub-components,
organized as shown below:
+----------------------+
| |
| North |
| |
+----------------------+
| | | |
| West | Center | East |
| | | |
+----------------------+
| |
| South |
| |
+----------------------+
When a component is added to a container that uses the Border Layout,
the area in which to position the component can be specified.
For example, in the program above, the statement "add(msgLabel, "North");"
is used to add the Label component to the top (North) of the Frame.
If one or more of the 5 areas are not used, the other areas expand to fill
up the space.
The Border Layout is the default layout for Frames.
buttonPanel.setLayout(new GridLayout(1,2));
sets the layout of the buttonPanel object to be a Grid Layout that contains
1 row and 2 columns.
The statement:
buttonPanel.setLayout(new FlowLayout( FlowLayout.CENTER ));
sets the layout of the buttonPanel object to be a Flow Layout in which
items in an incomplete row are centered.
Graphics
import java.awt.*;
public class Draw extends Frame {
// constructor
public Draw() {
// set the size of the frame and make it visible
setSize( 300, 300 );
setVisible( true );
}
public void paint(Graphics g) {
g.setColor(Color.red);
g.fillArc(150, 40, 20, 20, 0, 360);
g.drawLine(160, 60, 160, 110);
g.drawLine(160, 110, 145, 160);
g.drawLine(160, 110, 175, 160);
g.drawLine(130, 75, 190, 75);
g.setColor(Color.green);
g.drawString("This is George", 110, 180);
}
// main
public static void main( String[] args ) {
new Draw();
}
}
Note that the paint method has one parameter, a
Graphics object.
In the example, the actual parameter is the "graphics context"
associated with the Frame.
By calling the various draw methods of the Graphics object,
you can cause various shapes to appear in the Frame.
As mentioned above, you can redefine the paint method of any subclass of a Component. So, for example, you could create a button with the stick figure on it (in addition to the button label) by defining a subclass of Button, and redefining its paint method:
import java.awt.*; class MyButton extends Button { // 1-arg constructor: s is the button label public MyButton(String s) { super(s); } public void paint(Graphics g) { g.setColor(Color.red); g.fillArc(150, 20, 20, 20, 0, 360); g.drawLine(160, 40, 160, 90); g.drawLine(160, 90, 145, 140); g.drawLine(160, 90, 175, 140); g.drawLine(130, 55, 190, 55); } } public class PaintButton extends Frame { private MyButton b = new MyButton("George"); // constructor public PaintButton() { // add the button add(b); // set the size of the frame and make it visible setSize( 300, 300 ); setVisible( true ); } // main public static void main( String[] args ) { new PaintButton(); } }More typically, a subclass of the Canvas component (a blank rectangle) is used for drawing.
Solutions to Self-Study Questions
Test Yourself #1
Question 1.
// modified HelloWorld program that writes the (single) command-line arg
// instead of writing Hello World!
import java.awt.*;
public class HelloWorld1 extends Frame {
private Label text;
// constructor
public HelloWorld1(String arg) {
// create a label containing "Hello World!", with the text centered
text = new Label(arg, Label.CENTER);
// add the label to the Frame
add(text);
// set the size of the frame and make it visible
setSize( 300, 100 );
setVisible( true );
}
// main
public static void main( String[] args ) {
new HelloWorld1(args[0]);
}
}
Question 2.
// modified HelloWorld program in which the background color is red
// and the color of the text is blue
import java.awt.*;
public class HelloWorld2 extends Frame {
private Label text;
// constructor
public HelloWorld2() {
// create a label containing "Hello World!", with the text centered
text = new Label("Hello World!", Label.CENTER);
// set the background and foreground colors of the label
text.setBackground(Color.red);
text.setForeground(Color.blue);
// add the label to the Frame
add(text);
// set the size of the frame and make it visible
setSize( 300, 100 );
setVisible( true );
}
// main
public static void main( String[] args ) {
new HelloWorld2();
}
}