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:
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();
}
}
class (select the java.awt package, then the
Frame class in the
on-line java documentation for more information.)
A Frame corresponds to a window on
your screen with a title and a border. The way it looks will
depend on how your system is set up to display windows
(e.g., it may have controls to permit resizing, etc).
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:
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.
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 (see the on-line java documentation for more information about each of them.):
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:
class ExitButtonListener implements ActionListener {starts the definition of class ExitButtonListener, which is an implementation of the ActionListener interface.
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:
exitButton.addActionListener(exitListener);associates the ActionListener named exitListener with the Button object named exitButton.
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.
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(); } }
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:
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); } }
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):
+----------------------+ | | | 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.
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:
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();
}
}