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.
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(); } }
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:
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:
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.
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(); } }
// modified Hello1 program that includes a TextField instead of a Label, and // a "reset" button to change the displayed text back to "Hello World!" import java.awt.*; import java.awt.event.*; public class Hello1 extends Frame { private TextField text; private Button resetButton; // constructor public Hello1() { // create a TextField containing "Hello World!", // and add it to the top of the Frame text = new TextField("Hello World!"); add(text, "North"); // create the reset button and add it to the bottom of the Frame resetButton = new Button("reset"); add(resetButton, "South"); // create a listener for the reset button, and associate that // listener with the reset button ResetButtonListener resetListener = new ResetButtonListener(); resetButton.addActionListener(resetListener); // set the size of the frame and make it visible setSize( 300, 100 ); setVisible(true); } // define the listener for the reset button class ResetButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { // this method will be called when the reset button is clicked; // change the text back to "Hello World!" text.setText("Hello World!"); } } public static void main(String [] args) { new Hello1(); } }
Question 1. // modified ChangeFont program that uses a Flow Layout for the Frame // instead of the default Border Layout import java.awt.*; import java.awt.event.*; public class ChangeFont1 extends Frame { private Font plainFont, boldFont, italicFont, boldItalicFont; private List fontList; private Panel buttonPanel; private Button resetButton, exitButton; private Label msgLabel; // constructor public ChangeFont1() { // give this frame a Flow Layout setLayout( new FlowLayout(FlowLayout.LEFT)); // 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 to the frame msgLabel = new Label("This text will change font"); msgLabel.setFont(plainFont); add(msgLabel); // create the List of fonts and add it to the Frame fontList = new List(); fontList.add("bold"); fontList.add("italic"); fontList.add("bold italic"); add(fontList); // 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 Frame buttonPanel = new Panel(); buttonPanel.setLayout(new GridLayout(1,2)); buttonPanel.add(resetButton); buttonPanel.add(exitButton); add(buttonPanel); // 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 ChangeFont1(); } } Question 2. // modified ChangeFon program that uses checkboxes instead of a list to // display the font choices import java.awt.*; import java.awt.event.*; public class ChangeFont2 extends Frame { private Font plainFont, boldFont, italicFont, boldItalicFont; private Panel buttonPanel; private Panel fontPanel; private Button resetButton, exitButton; private Label msgLabel; private CheckboxGroup checkBoxes; private Checkbox boldBox, italicBox, boldItalicBox; // constructor public ChangeFont2() { // 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 a Panel to hold the CheckboxGroup // and add it in the middle of the Frame fontPanel = new Panel(); add(fontPanel, "Center"); // create the CheckboxGroup and its Checkboxes // all Checkboxes are initially "off" (unpushed) checkBoxes = new CheckboxGroup(); boldBox = new Checkbox("bold font", checkBoxes, false); italicBox = new Checkbox("italic font", checkBoxes, false); boldItalicBox = new Checkbox("bold italic font", checkBoxes, false); // add the Checkboxs to the Panel fontPanel.add(boldBox); fontPanel.add(italicBox); fontPanel.add(boldItalicBox); // 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 checkboxes and for the two buttons ResetButtonListener resetListener = new ResetButtonListener(); ExitButtonListener exitListener = new ExitButtonListener(); BoxListener boxListener = new BoxListener(); // use the addXXXListener methods of the checkboxes and the buttons // to associate each listener with the appropriate object resetButton.addActionListener(resetListener); exitButton.addActionListener(exitListener); boldBox.addItemListener(boxListener); italicBox.addItemListener(boxListener); boldItalicBox.addItemListener(boxListener); // 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 BoxListener implements ItemListener { public void itemStateChanged(ItemEvent e) { // this method will be called when one checkbox is // pushed using the mouse; // determine which checkbox it was and set the font accordingly Checkbox source = (Checkbox)e.getSource(); if (source == boldBox) { msgLabel.setFont(boldFont); } else if (source == italicBox) { msgLabel.setFont(italicFont); } else if (source == boldItalicBox) { msgLabel.setFont(boldItalicFont); } else { // shouldn't get here System.err.println("unknown checkbox"); System.exit(1); } } } public static void main(String [] args) { new ChangeFont2(); } }