This appendix describes the components of the Abstract Window Toolkit (AWT) that have been replaced by the Swing components. The AWT components are described here because there are two circumstances when you may run into them: when you maintain old code, and when you are asked to write code that must run in the obsolete JDK 1.0 environment.
The Java AWT interface offers the functions that are common to all window systems. The AWT code then uses the underlying native (or “peer”) window system to actually render the screen images and manipulate GUI objects. The AWT thus consists of a series of abstract interfaces along with Java code to map them into the actual native code on each system. This is why it is an abstract window toolkit; it is not tailored for a specific computer but offers the same API on all.
The AWT currently requires the native window system to be running on the platform because it uses the native window system to support windows within Java. Figure B-1 shows how the AWT interacts with the native window system.
Mnemonic: Peer objects let your Java runtime “peer” at the underlying window implementation. They are only of interest to people porting the Java Development Kit. To a Java applications programmer, all window system code is written in Java.
In this appendix, I use the PC term control to mean the group of all the GUI things that users can press, scroll, choose between, type into, draw on, etc. In the Unix world, a control is called a widget. Neither control nor widget is a Java term, and in reality there is no control class. It’s so useful, however, to be able to say “control” instead of “GUI thing that the user interacts with” or “Components plus menus” that we use the term here wherever convenient. Because each control is a subclass of Component
, each control (button, etc.) also inherits all the methods and data fields of Component
.
The important top-level classes that make up the AWT are shown in Figure B-2.
The basic idea is that you:
Declare controls. You can subclass them to add to the behavior, but this is often not necessary.
Add the controls to a container. Again, subclassing is possible but frequently not necessary.
Implement an interface to get the event handler that responds to control activity.
We will look at all the dozen or so individual controls in depth.
The controls are: Button
, Canvas
, Checkbox
, Choice
, Label
, List
, Scrollbar
, TextField
, TextArea
, and the variations on Menu
. Each control has methods appropriate to what it does. The Scrollbar
control has methods to set the width, orientation, and height of scrollbars, for instance. We'll examine each individual control in depth later in the appendix. One obvious control that is missing is a control into which you can write HTML and have it automatically formatted. More controls were added with the Java Foundation Classes, adopted from Netscape’s Internet Foundation Classes. These were announced for the JDK 1.2 release.
At this point we now have enough background knowledge of the various GUI elements to present an in-depth treatment of how they talk to your code. Read on for the fascinating details!
We now start looking at individual controls in detail and to describe the kinds of event they can generate. Almost the whole of window programming is learning about the different objects that you can put on the screen (windows, scrollbars, buttons, etc.) and how to drive them. This section explains how to register for and process the events (input) that you get back from controls. A control isn’t a free-standing thing; it is always added to a Container
such as an Applet
, Frame
, Panel
, or Window
, with a method call like MyContainer.add( myComponent )
. The controls that we will cover here are buttons, text fields, scrollbars, mouse events, and so on. The class hierarchy is quite flat. The controls shown in Figure B-3 are all subclasses of the general class Component
that we have already seen.
These classes are the controls or building blocks from which you will create your GUI. What you do with all these components is:
Add them to a container (usually Frame
or Applet
), then display the container with the show()
method.
Register your event handler, using the addXxxListener()
method of the control. This will tell the window system which routine of yours should be called when the user presses buttons, makes selections, etc., to process the event.
Fortunately, both of these activities are quite straightforward, and we’ll cover them here in source code, words, and pictures. The add
method can be applied to a Frame
in an application, like this:
Frame f = new Frame(); ... f.add( something );
Or, it can be applied to the Applet
's panel in an applet, like so:
public static void init () { this.add( something );
Or, more simply:
public static void init () { add( something );
Recall the Applet
life cycle. That discussion made clear that there is an init()
method which each Applet
should override. It will be called when the Applet is loaded, and it is a good place to place the code that creates these GUI objects. We will use init()
for that purpose.
Whenever a user operates a Component
(presses a button, clicks on a choice), an event is generated. The XxxEvent
argument is a class that can be seen in the awt/event
directory. It contains much information about the coordinates of the event, the time it occurred, and the kind of event that it was. If the event was a keypress, it has the value of the key. If the event was a selection from a list, it has the string chosen.
Having explained the general theory of controls and control events, let’s take a look at how they appear on the screen and the typical code to handle them.
What it is: This is a GUI button. You can program the action that takes place when the button is pressed
What it looks like on screen:
The code to create it:
Button b = new Button("peach"); add(b);
The code to retrieve user input from it:
MyBHClass myButtonHandler = new MyBHClass(); public void init() { add(apple); apple.addActionListener(myButtonHandler); } } class MyBHClass implements java.awt.event.ActionListener { int i=1; public void actionPerformed(ActionEvent e) { // this gets called when button pressed... String s = e.paramString(); // gets the button label } }
An event-handler this small would typically be written using an inner class, and we will use inner classes for the rest of the examples.
In an applet, you will typically override the init()
method and, inside it, call the add()
method to add these objects to your Applet’s panel. In an application, there is no predetermined convention, and you can set the objects where you like. (Note: in future examples in this section, we won’t bother repeating the context that this is part of the init()
method in an applet).
Program an “Alice in Wonderland” applet: a panel with two buttons, one of which makes the panel grow larger, the other smaller. The Component
method
setSize(int, int)
will resize a Panel
or other Container
. (Easy—about 20 lines of code.)
What it is:A Canvas
is a screen area that you can use for drawing graphics or receiving user input. A Canvas
usually is subclassed to add the behavior you need, especially when you use it to display a GIF or JPEG image. A Canvas
contains almost no methods. All its functionality is either inherited from Component
(setting font, color, size) or from functionality you add when you extend the class.
To draw on a canvas, you supply your own version of the paint(Graphics g)
method. To do that, you need to extend the class and override the paint()
method for this Canvas
. A more descriptive name for the paint()
method would be do_this_to_draw_me()
. That gives you a Graphics context (the argument to paint()
), which is used in all drawing operations. The many methods of Graphics let you render (the fancy graphics word for “draw”) lines, shapes, text, etc., on the screen.
What it looks like on screen:
The screen capture is not very exciting, merely showing a rectangular area that has been highlighted with a different color to make it visible (see code below). Canvases are relatively inert until you extend them and use them to display images or do other graphics programming.
The code to create it: This code gives the Canvas
a red color, so you can distinguish it from the Panel
(as long as your Applet panel isn’t red to begin with, of course). The code then gives the Canvas
a size of 80 pixels wide by 40 pixels high and adds it to the Applet
.
Canvas n = new Canvas(); n.setBackground(Color.red); n.setSize(80,40); add(n);
Note that you cannot draw on objects of class Canvas
. You must extend Canvas
and override the paint()
method and do your drawing in that routine. The paint() method needs to contain all the statements to draw everything that you want to see in the canvas at that time. Here is how you would extend Canvas to provide a surface that you can draw on:
// <applet code=can.class width=250 height=100> </applet>
import java.awt.*;
import java.applet.*;
public class can extends Applet {
myCanvas c = new myCanvas();
public void init() {
c.setSize(200,50);
add(c);
}
}
class myCanvas extends Canvas{
public void paint(Graphics g) {
g.drawString("don't go in the basement", 10,25);
g.drawLine(10,35, 165,35);
}
}
You can compile and execute this by typing
javac can.java appletviewer can.java
A window like this is displayed on the screen:
A Canvas
is similar to a Panel
, in that you can draw on it, render images, and accept events. A Canvas
is not a container, however, so you cannot add other components to it. Here is how you would accept mouse events on a Canvas.
// <applet code=can.class width=250 height=100> </applet> import java.awt.*; import java.awt.event.*; import java.applet.*; public class can extends Applet { Canvas c = new Canvas(); public void init() { c.setSize(200,50); c.setEnabled(true); c.setBackground(Color.blue); c.addMouseListener ( new MouseListener() { public void mouseEntered(java.awt.event.MouseEvent e) {System.out.println(e.toString() );} public void mouseClicked(java.awt.event.MouseEvent e) {} public void mousePressed(java.awt.event.MouseEvent e) {} public void mouseReleased(java.awt.event.MouseEvent e) {} public void mouseExited(java.awt.event.MouseEvent e) {} }); add(c); } }
The preceding code handles the event fired when the mouse enters the blue canvas. If you run it, you'll see something like this.
% appletviewer can.java
java.awt.event.MouseEvent[MOUSE_ENTERED,(131,49),mods=0,clickCount
=0] on canvas0
Here is an example showing how the MouseAdapter
class is used when all we are interested in is the mouse entering the Canvas
.
// <applet code=can.class width=250 height=100> </applet> import java.awt.*; import java.awt.event.*; import java.applet.*; public class can extends Applet { Canvas c = new Canvas(); public void init() { c.setSize(200,50); c.setEnabled(true); c.setBackground(Color.blue); c.addMouseListener ( new MouseAdapter() { public void mouseEntered(java.awt.event.MouseEvent e) {System.out.println(e.toString() );} }); add(c); } }
Here is an example of how a game program might capture individual key presses in an applet as they are made. Note that the output is to System.out
, which isn’t displayed in a browser unless you bring up the right window. This example is best run in the applet viewer.
// <applet code=game.class height=200 width=300> </applet> import java.awt.*; import java.awt.event.*; import java.applet.*; public class game extends Applet { public void init() { requestFocus(); // a component must have the focus to get //key events addKeyListener( new KeyAdapter() { public void keyPressed(java.awt.event.KeyEvent e) { System.out.println("got "+e.getKeyChar()); } } // end anon class ); // end method call } }
The requestFocus()
call is a Component
method to ask that keyboard input be directed to this control. Having to explicitly ask for the focus is a change from JDK 1.0.2. The Component
must be visible on the screen for the requestFocus()
to succeed. A FocusGained
event will then be delivered if there's a listener for it.
Let’s continue with our description of the individual controls.
What it is: A checkbox screen object that represents a boolean choice: “pressed” or “not pressed” or “on” or “off.” Usually some text explains the choice. For example, “Press for fries” would have a Checkbox “button” allowing yes or no.
What it looks like on screen:
The code to create it:
Checkbox cb = new Checkbox("small"); add(cb);
The code to retrieve user input from it: Checkbox generates ItemEvent
. The code to register an ItemListener
looks like this:
// <applet code=excheck.class width=250 height=100> </applet> import java.awt.*; import java.awt.event.*; import java.applet.*; public class excheck extends Applet { Checkbox c1 = new Checkbox("small"); public void init() { c1.addItemListener ( new ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent ie) { System.out.println(ie.paramString() );} }); add(c1); } }
In this example, as in most of them, we simply print out a String representation of the event that has occurred. Running the applet and clicking the checkbox will cause this output in the system console:
appletviewer excheck.java ITEM_STATE_CHANGED,item=small,stateChange=SELECTED ITEM_STATE_CHANGED,item=small,stateChange=DESELECTED
Handlers in real programs will do more useful actions: assign values, create objects, etc., as necessary. The ItemEvent contains fields and methods that specify which object generated the event and whether it was selected or deselected.
What it is: There is a way to group a series of checkboxes to create a Checkbox
Group
of radio buttons. The term “radio buttons” arises from the old manual station selection buttons in car radios. When you pressed in one of the buttons, all the others would pop out and be deselected. CheckboxGroups
work the same way.
What it looks like on screen:
On Windows 95, mutually-exclusive checkboxes are round, while multiple-selection checkboxes are square. This is one of those “look and feel” differences that vary between window systems.
The code to create it: You first instantiate a CheckboxGroup
object, then use that in each Checkbox
constructor, along with a parameter saying whether it is selected or not. This ensures that only one of those Checkbox buttons will be allowed to be on at a time.
// <applet code=excheck2.class width=250 height=100> </applet> import java.awt.*; import java.awt.event.*; import java.applet.*; public class excheck2 extends Applet { CheckboxGroup cbg = new CheckboxGroup(); Checkbox c1 = new Checkbox("small", false, cbg); Checkbox c2 = new Checkbox("medium", false, cbg); Checkbox c3 = new Checkbox("large", true, cbg); ItemListener ie = new ItemListener () { public void itemStateChanged(java.awt.event.ItemEvent ie) { System.out.println(ie.toString());} }; public void init() { c1.addItemListener ( ie ); c2.addItemListener ( ie ); c3.addItemListener ( ie ); add(c1); add(c2); add(c3); } }
Note here that we are using the same, one instance of an inner class as the handler for events from all three of these Checkboxes. It is common to have one handler for several related objects, and let the handler decode which of them actually caused the event. We couldn’t do this if we had created an anonymous class, because we would not have kept a reference to use in the later addItemListener()
calls.
What it is: This is a pop-up list, akin to a pull-down menu, which allows a selection from several text strings. When you hold down the mouse button on the choice, a list of all the other choices appears and you can move the mouse over the one you want.
What it looks like on screen:
Choices are very similar to the List
control. Lists look a little more like text; Choices look a little more like buttons and menus. When you click the mouse on a Choice
, it pops up the full range of choices, looking like this:
The code to create it:
<applet code=exchoice.class width=250 height=100> </applet> import java.awt.*; import java.awt.event.*; import java.applet.*; public class exchoice extends Applet { Choice c = new Choice(); public void init() { add(c); c.addItem("lemon"); c.addItem("orange"); c.addItem("lime"); ItemListener il = new ItemListener () { public void itemStateChanged(java.awt.event.ItemEvent ie) { System.out.println(ie.getItem()); } }; c.addItemListener ( il ); } }
Note that it is perfectly feasible to build the items in a Choice list dynamically. If you wanted to, you could build at runtime a Choice
representing every file in a directory. A control called FileDialog
does this for you, however.
What it is: This is a very simple component. It is just a string of text that appears on screen. The text can be left, right, or center aligned according to an argument to the constructor. The default is left aligned.
What it looks like on screen:
The code to create it:
// <applet code=exlabel.class width=250 height=100> </applet> import java.awt.*; import java.awt.event.*; import java.applet.*; public class exlabel extends Applet { String s = "Eat fresh vegetables"; Label l = new Label(s); public void init() { add(l); } }
Labels do not generate any events in and of themselves. However, it is possible to change the text of a label (perhaps in response to an event from a different component).
Labels are typically used as a cheap, fast way to get some text on the screen and to label other controls with descriptions or instructions. People often want to know how to get a multiline label (or a multiline button). There is no direct way. You will have to program the functionality in for yourself, by extending the class Canvas
or Component
to do what you want.
What it is: Lists are very similar to Choices, in that you can select from several text alternatives. With a Choice, only the top selection is visible until you click the mouse on it to bring them all up. With a List, many or all of the selections are visible on the screen with no mousing needed.
A List also allows the user to select one or several entries (single or multiple selection is configurable). A Choice only allows one entry at a time to be chosen.
What it looks like on screen:
The code to create it: This creates a scrolling list with three items visible initially and does not allow multiple selections at the same time (multiple selections is false).
//<applet code=exlist.class width=200 height=100> </applet> import java.awt.*; import java.awt.event.*; import java.applet.*; public class exlist extends Applet { List l = new List(3,false); public void init() { add(l); l.addItem("carrot"); l.addItem("parsnip"); l.addItem("sprout"); l.addItem("cabbage"); l.addItem("turnip"); ItemListener il = new ItemListener () { public void itemStateChanged(java.awt.event.ItemEvent ie) { System.out.println(ie.getItem() ); } }; l.addItemListener ( il ); } }
The code to retrieve user input from it: The ItemListener
is called when the selection is made by clicking on the list entry. Unlike a Choice, which returns the text string representing the selection, a List
selection event returns an integer in the range 0 to N, representing the selection of the zeroth to Nth item.
The List
class (not the ItemEvent
class) has methods to turn that list index into a String and to get an array containing the indexes of all currently selected elements.
public String getItem(int index); public synchronized int[] getSelectedIndexes();
What it is: A scrollbar is a box that can be dragged between two end points. Dragging the box, or clicking on an end point, will generate events that say how far along the range the box is.
You don't have to use Scrollbar
much, as scrollbars are given to you automatically on several controls (TextArea
, Choice
, and ScrollPane
). When you do use one, it is typically related by your code to some other control. When the user moves the scrollbar, your program reads the incoming event and makes a related change in the other control. Often, that involves changing the visual appearance, but it doesn’t have to. A scrollbar could be used to input numeric values between two end points.
What it looks like on screen:
The code to create it:
public void init() { Scrollbar s = new Scrollbar(Scrollbar.VERTICAL,20,10,5,35); add(s);
The arguments are:
whether the bar should go up Scrollbar.VERTICAL
or along Scrollbar.HORIZONTAL
the initial setting for the bar (here, 20), which should be a value between the high and low ends of the scale
the length of the slider box (here, 10)
the value at the low end of the scale (here, 5)
the value at the high end of the scale (here, 35)
The code to retrieve user input from it: Scrollbars have various methods for getting and setting the values, but the method you’ll use most is public int getValue()
. There is a method of this name in both the Scrollbar
class and the AdjustmentEvent
class. When you call it, it returns the current value of the Scrollbar
or (when you invoke it on the AdjustmentEvent
object), the value that it had when this event was generated.
Here is an example of using Scrollbar
to input a numeric value. It draws a simple bar graph by resizing a canvas according to the scroll value.
// <applet code=A.class height=200 width=300> </applet> import java.awt.*; import java.awt.event.*; import java.applet.*; public class A extends Applet { public void init() { resize(250,200); final Canvas n = new Canvas(); n.setBackground(Color.red); n.setSize(20,20); add(n); Scrollbar s = new Scrollbar(Scrollbar.VERTICAL,10,20,1,75); add(s); s.addAdjustmentListener( new AdjustmentListener() { public void adjustmentValueChanged(AdjustmentEvent ae) { System.out.println("ae="+ae); n.setSize( 20, ae.getValue() *5 ); repaint(); } } ); } }
Now that JDK 1.1 has introduced the ScrollPane
container type, scrollbars don't need to be programmed explicitly nearly so much.
What it is: A TextField
is a field into which the user can type a single line of characters. The number of characters displayed is configurable. A TextField can also be given an initial value of characters. Changing the field is called editing it, and editing can be enabled or disabled.
The TextField
component sets its background color differently, depending on whether the TextField
is editable, or not. If the Textfield
can be edited, the background is set to backgroundColor.brighter()
; if it is not editable, the whole text field is set to the same color as the background color.
What it looks like on screen:
The code to create it: This code creates a TextField
with eight characters showing, and initialized to with the characters “apple”. You can type different characters in there and more than eight, but only eight will show at a time.
TextField tf = new TextField("apple",8); add(tf);
The code to retrieve user input from it: A TextField
causes an event when a Return is entered in the field. At that point, the ActionEvent
method getActionCommand()
will retrieve the text.
//<applet code=extf.class height=100 width=200> </applet> import java.applet.*; import java.awt.*; import java.awt.event.*; public class extf extends Applet { TextField tf = new TextField("apple",8); public void init() { add(tf); tf.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("field is" +e.getActionCommand()); } } // end anon class ); // end method call } }
Remember that any component can register to receive any kind of event. A useful thing you might want to do is register a KeyListener
for the text field. You could use this to filter incoming keystrokes, perhaps validating them. The code below will make the text field beep if you type any non-numeric input.
//<applet code=extf2.class height=100 width=200> </applet> import java.applet.*; import java.awt.*; import java.awt.event.*; public class extf2 extends Applet { TextField tf = new TextField("numbers only",14); public void init() { add(tf); tf.addKeyListener( new KeyAdapter() { public void keyPressed(KeyEvent e) { char k = e.getKeyChar(); if (k<'0' || k>'9'){ tf.getToolkit().beep(); e.setKeyChar('0'), } } } // end anon class ); // end method call tf.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("got "+e.getActionCommand()); } } // end anon class ); // end method call } }
A KeyListener
is registered with the text field. As keystrokes come in, it examines them and converts any non-numerics to the character “0”, effectively forcing the field to be numeric. An ActionListener
is registered with the text field too. The ActionListener
retrieves the entire numeric string when the user presses Return.
Note: A bug in the Windows 95 version of JDK 1.1.1 prevents the setKeyChar()
method from changing the character to zero.
A better approach would be to allow the character to be typed, and then use the getText()
and setText()
methods of the TextComponent
parent class to remove the non-numeric characters.
Finally, note the setFont()
method, which will use a different font in the component. A typical call looks like this:
myTextArea.setFont( new Font("FONTNAME", FONTSTYLE, FONTSIZE) );
Where FONTNAME
is the name of the font (e.g., Dialog, TimesRoman) as a String. FONTSTYLE
is Font.PLAIN
, Font.ITALIC
, Font.BOLD
or any additive combination (e.g., Font.ITALIC
+ Font.BOLD
). FONTSIZE
is an int representing the size of the font, (e.g., 12 means 12 point).
What it is: A TextField that is several lines long. It can be set to allow editing or read-only modes.
What it looks like on screen:
The code to create it:
TextArea t = new TextArea("boysenberry", 4, 9); add(t);
This creates a text area of four lines, each showing nine characters. The first line shows the first nine characters of the string “boysenberry.” You can place text on the next line in the initializer by embedding a ‘ ’ character in the string.
TextAreas automatically come with scrollbars, so you can type an unbounded amount of text.
//<applet code=exta.class height=100 width=200> </applet> import java.applet.*; import java.awt.*; import java.awt.event.*; public class exta extends Applet { TextArea ta = new TextArea("boysenberry", 4, 9); public void init() { add(ta); ta.addTextListener( new TextListener() { public void textValueChanged(java.awt.event.TextEvent e) { System.out.println("got "+ta.getText()); } } // end anon class ); // end method call } }
Like all of these controls, TextArea
s use the underlying native window system control and are subject to the same limitations of the underlying window system. Under Microsoft Windows, TextAreas can only hold 32K of characters, less a few K for overhead. A big benefit of moving to peerless, pure Java components is to lose platform-specific limitations.
Unlike a TextField
, a TextArea might have embedded newlines, so a newline can’t be used to cause the event that says, “I am ready to give up my value.” The same solution is used as with a multiple-selection list. Use another control, say, a button or checkbox, to signal that the text is ready to be picked up. Alternatively, as in this example, you simply can pull in the text for the whole area as each new character comes in.
In an eccentric design choice, menus are not Components—they are an on-screen thing that isn’t a subclass of Component
. This inconsistency was originally perpetrated to reflect the same design limitation in Microsoft Windows, namely, menus in Win32 are not first-class controls.
The terminology of menus is shown in Figure B-4.
The Menu-related classes match the terminology shown in Figure B-4. We have a MenuBar
class on which menus can be placed. Each menu can have zero or more MenuItems
. Because menus aren’t Components, we have two additional classes: MenuComponent
and MenuContainer
.
What it is: A Frame can hold a MenuBar
, which can have several pull-down menus. The MenuBar
has its top edge on the top edge of the Frame
, so if you add anything to (0,0) on the Frame
, the MenuBar
will obscure it. The MenuBar
holds the names of each Menu
that has been added to it. Each pull-down menu has selectable MenuItems
on it, each identified by a String. You can populate a menu with menu items and also with other menus. The second case is a multilevel menu.
What it looks like on screen:
The code to create it:
//<applet code=exmenu.class height=100 width=200> </applet> import java.applet.*; import java.awt.*; import java.awt.event.*; public class exmenu extends Applet { Frame f = new Frame("my frame"); MenuBar mb = new MenuBar(); Menu nuts = new Menu("nut varieties", /*tearoff=*/ true); public void init() { nuts.add(new MenuItem("almond")); nuts.add(new MenuItem("-") ); // a separator in the menu nuts.add(new MenuItem("filbert")); nuts.add(new MenuItem("pecan")); mb.add(nuts); f.setSize(500,100); f.setMenuBar(mb); f.show();
The code to retrieve user input from it MenuItems
can be handled by registering an Event
with the Menu
, like this:
nuts.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("field is "+e.getActionCommand()); } } // end anon class ); // end method call
A tear-off menu is one that remains visible even after you take your finger off the mouse button and click elsewhere. Not all window systems support tear-off menus, and the boolean is simply ignored in that case. Under CDE (the Unix window system), a tear-off menu is indicated by a dotted line across the top of the menu.
An alternative kind of MenuItem
is a CheckboxMenuItem
. This variety of MenuItem
allows on/off selection/deselection, possibly several at once. It looks like the Checkbox
control that we saw earlier.
What it looks like on screen:
As the name suggests, this is a menu item that can be checked off or selected (like a checkbox). You receive ItemEvents from this kind of control, to say whether it is currently selected or not. Other than that, it works like a MenuItem
, because it is a subclass of MenuItem
.
With all these Menu
gadgets, there are more methods than are shown here. A menu item can be disabled so it can’t be selected, then later it can be enabled again.
There are menu item shortcuts, which are single-character keyboard accelerators that cause a menu event when you type them, just as if you had selected a menu item. A menu item shortcut can be set and changed with methods in the MenuItem
class.
MenuItem myItem = new MenuItem("Open..."); myMenu.add(myItem); myItem.setShortcut(new MenuShortcut((int)'O', false);
Note that under Windows, the standard controls parse their text names for special characters that indicate a letter in the control's text should be underlined (indicating a shortcut). For OS/2, the special character is ∼; for Win32, it is &. Java does not support this feature.
The code to create it:
//<applet code=exmenu2.class height=100 width=200> </applet> import java.applet.*; import java.awt.*; import java.awt.event.*; public class exmenu2 extends Applet { Frame f = new Frame("my frame"); MenuBar mb = new MenuBar(); Menu car = new Menu("car options", /*tearoff=*/ true); public void init() { CheckboxMenuItem cbm1 = new CheckboxMenuItem( "auto transmission"); CheckboxMenuItem cbm2 = new CheckboxMenuItem( "metallic paint"); CheckboxMenuItem cbm3 = new CheckboxMenuItem( "wire wheels"); options action = new options(); cbm1.addItemListener(action); cbm2.addItemListener(action); cbm3.addItemListener(action); car.add(cbm1); car.add(cbm2); car.add(cbm3); mb.add(car); f.setSize(500,100); f.setMenuBar(mb); f.show(); } } class options implements ItemListener { public void itemStateChanged(ItemEvent e) { System.out.println("field is "+e.toString()); } }
As well as pull-down menus, most modern systems have pop-up menus, which are menus that are not attached to a menu bar on a Frame. Pop-up menus are usually triggered by clicking or holding down a mouse button over a Container. One of the mouse event methods is PopupTrigger()
, allowing you to check on this eventuality and if so display the pop-up menu at the (x,y) coordinates of the mouse. On Unix, the right mouse button is the trigger for a pop-up.
Pop-up menus, introduced in JDK 1.1, made menus much more useful in applets. Until then, people had tended not to use menus in applets, because the top-level container is a Panel
(not a Frame
) and so can’t have a MenuBar
added to it. You can create Frames in applets, but they are independent windows, floating free on the desktop.
What it looks like on screen:
The code to create it:
//<applet code=expop.class height=100 width=200> </applet> import java.applet.*; import java.awt.*; import java.awt.event.*; public class expop extends Applet { PopupMenu choc = new PopupMenu("varieties"); public void init() { choc.add(new MenuItem("milk")); choc.add(new MenuItem("dark")); choc.add(new MenuItem("belgian")); add(choc); final Applet app = this; addMouseListener( new MouseAdapter() { public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) choc.show(app,30,30); } } ); choc.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("field is "+e.getActionCommand()); } } // end anon class ); // end method call } }
The previous section describes all the controls of JDK 1.1, now let’s take a look at the Containers that hold them. To refresh our memories, the class hierarchy for containers is as shown in Figure B-5.
On the following pages, we will outline each of these containers, suggest typical uses, and show code examples. Container
is the class that groups together a number of controls and provides a framework for how they will be positioned on the screen. Container
has fields and methods to deal with:
The layout manager used to automatically position controls
Forcing the layout to be done
Refreshing the appearance on screen
Adding a ContainerListener
for ContainerEvents
Adding, removing, and getting a list of any of the controls
Size (current, preferred, minimum, and maximum)
Requesting the window focus
A paint()
routine that will render it on the screen
Container
has methods to get and set many of these attributes. Since a Container
is a subclass of Component
. It also has all the Component
fields. You can and should review the Container
methods by running
javap java.awt.Container
On the following pages we will review the different kinds (subclasses) of Container
in the AWT. Containers are for holding, positioning, and displaying all the controls you add to them. When you have finished adding or changing the components in a Container, you typically call these three methods on the Container:
myContainer.invalidate(); // tell AWT it needs laying out myContainer.validate(); // ask AWT to lay it out myContainer.show(); // make it visible
These methods aren’t needed if you are just adding to an applet, but you will need to use them in your more complicated programs.
What it is: ScrollPane
is a Container
that implements automatic horizontal and/or vertical scrolling for a single child component. You will create a ScrollPane
, call setSize()
on it to give it a size, then add some other control to it. The control you add will often be a canvas with an image, though it can be any single component (such as a panel full of buttons).
You can ask for scrollbars never, as needed, or always. Note the inconsistent use of capitals; we have a Scrollbar
but a ScrollPane
.
What it looks like on screen:
The code to create it:
//<applet code=exsp.class width=150 height=130 > </applet> import java.awt.*; import java.applet.*; import java.awt.event.*; public class exsp extends Applet { public void init() { Image i = getImage(getDocumentBase(),"puppy.jpg"); myCanvas mc = new myCanvas(i); ScrollPane sp = new ScrollPane(); sp.setSize(120,100); sp.add(mc); sp.add(mc); add(sp); } } class myCanvas extends Canvas { Image si; public myCanvas(Image i) { this.setSize(200,200); si=i;} public void paint(Graphics g) { g.drawImage(si,0,0,this);} }
What it is: This Container
is a totally blank window. It doesn’t even have a border. You can display messages by putting Labels on it. Typically you don’t use Window
directly but use its more useful subclasses (Frame
and Dialog
).
Windows can be modal, meaning they prevent all other windows from responding until they are dealt with (usually with a checkbox). Window
has a few methods to do with bringing it to the front or back, packing (resizing to preferred size,) or showing (making it visible).
What it looks like on screen:
The code to create it:
//<applet code=exwin.class width=275 height=125 > </applet> import java.awt.*; import java.applet.*; import java.awt.event.*; public class discern extends Applet { public void init() { Component c = this.getParent(); while (Connell && !(c instanceof Frame)) c=c.getParent(); Window w = new Window( (Frame)c); w.setBounds(50,50,250,100); w.show(); } }
The public constructor of Window
needs to know the Frame
that it belongs to, so we walk up the parent tree until we find it. This repeated getParent()
code is a Java idiom you will see in AWT code from time to time.
For security purposes, the browser will typically make sure any Window
or subclass of Window
popped up from an untrusted applet will contain a line of text warning that it is an “untrusted window” or an “applet window.” This message ensures the user of an applet will never be in any doubt about the origin of the window. Without this clear label, it would be too easy to pop up a window that looked like it came from the operating system and ask for confidential information to send back to the applet server. It is not possible for an applet to prevent this security label from being shown.
What it is:A Frame
is a window that also has a title bar, a menu bar, a border (known as the inset), and that can be closed to an icon. In JDK 1.0.2, the cursor could be set for a Frame
(only). In JDK 1.1, this restriction was lifted, and the cursor can now be set for each individual Component
.
The origin of a Frame
is its top left corner. You can draw on a Frame
just as you can on a Canvas
. When you create a Frame
, it is not physically displayed inside the applet or other Container but is a separate free-floating window on the monitor.
What it looks like on screen:
The code to create it:
import java.awt.*; public class exfr { static Frame f = new Frame("cherry"); public static void main(String[] a) { f.setBounds(100,50,300,100); f.show(); } }
Note that this is an application, but frames can equally be displayed from an applet, as in the code below.
//<applet code=exfr2.class width=275 height=125 > </applet> import java.awt.*; import java.applet.*; import java.awt.event.*; public class exfr2 extends Applet { public void init() { Frame f = new Frame("Frame of an Applet"); f.setBounds(100,50,300,100); f.show(); } }
What it looks like on screen:
Here is how you associate a file containing an icon with a Frame, so that when you close the Frame, it collapses to the icon.
// load the image from a file Toolkit t = MyFrame.getToolkit(); Image FrameIcon = t.getImage(filename); if (FrameIcon != null) { // change the icon MyFrame.setIconImage(FrameIcon); }
The file name should point to a GIF or JPEG file that is the icon you want to use. Typically, this image will be thumbnail-sized, 32 x 32 pixels or so.
You will usually want to put in the three or four lines of code that deal with a top level window (Frame, etc) being quit or destroyed (when the user has finished with it—this is usually a standard choice on the frame menu bar).
The code looks like:
class wl extends WindowAdapter { Window w; public wl(Window w) { this.w=w; } public void windowClosed(WindowEvent e) { w.setVisible(false); w=null; } }
You could also exit the application. That would be appropriate when the user quits from the top-level window. For a lower-level window, the right thing to do may be to hide the window and release the resource for garbage collection by removing any pointers to it.
What it is: A Panel
is a generic container that is always in some other container. It does not float loose on the desktop, as Window
and Frame
do. A panel is used when you want to group several controls inside your GUI. For example, you might have several buttons that go together, as shown in the next screen capture. Adding them all to a Panel allows them to be treated as one unit, all displayed together, and laid out on the screen under the same set of rules.
The code to create it:
//<applet code=expan.class width=275 height=125 > </applet> import java.awt.*; import java.applet.*; import java.awt.event.*; public class expan extends Applet { public void init() { final Panel p = new Panel(); add(p); invalidate(); validate(); final Button b1 = new Button("beep"); b1.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { b1.getToolkit().beep(); } } // end anon class ); // end method call Button b2 = new Button("change color"); b2.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { Color c = p.getBackground()==Color.red? Color.white: Color.red; p.setBackground( c ); b1.setEnabled(false); } } // end anon class ); // end method call p.add(b1); p.add(b2); } }
This code displays two buttons, one of which beeps, and the other of which changes the panel color. Once the panel color has been changed, the beeping button is disabled. Note how that changes its appearance on the screen.
What it looks like on screen:
Applet is a subclass of Panel. The major thing this says is that applets come ready-made with some GUI stuff in place. Figure B-6 is another example screen capture of an applet.
Here is the code that created that applet:
import java.awt.*; import java.applet.*; public class plum extends Applet { public void init() { setBackground(Color.green); resize(250,100); } public void paint(Graphics g) { g.drawString(”I am in the Applet“, 35,15); } }
One advantage of an applet over an application for a GUI program is that you can start adding components and displaying them without needing to create an underlying backdrop, as one already exists.
Here are some popular methods of Applet:
public URL getDocumentBase() //the URL of the page containing the applet public URL getCodeBase() //the URL of the applet code public String getParameter(String name) public void resize(int width, int height) public void showStatus(String msg) public Image getImage(URL url) //bring in an image public Image getImage(URL url, String name) public AudioClip getAudioClip(URL url) //bring in a sound file public void play(URL url)
Applet has other methods too. The source can be seen in
$JAVAHOME/src/java/applet/Applet.java
What it is: A Dialog
is a top-level, free-floating window like Frame
. Dialog
lacks the menu bar and iconification of Frame
. A Dialog
is the way you show a line of text to the user, often relating to the most recent action, such as, “Really overwrite the file? Y/N.”
According to a boolean mode parameter in the constructor, a Dialog
can be modal or modeless. Modal Dialogs disable all other AWT windows until the modal Dialog is no longer on the screen.
What it looks like on screen:
The code to create it:
//<applet code=exdial.class width=275 height=125 > </applet> import java.awt.*; import java.applet.*; import java.awt.event.*; public class exdial extends Applet { public void init() { Component c = this.getParent(); while (c!=null && !(c instanceof Frame)) c=c.getParent(); final Dialog d = new Dialog((Frame)c); Checkbox c1 = new Checkbox("Click if you feel lucky today, punk"); c1.addItemListener ( new ItemListener() { public void itemStateChanged(java.awt.event.ItemEvent ie) { d.setVisible(false); } }); d.add(c1); d.setBounds(50,50, 280,100); d.show(); } }
What it is: FileDialog
is a Container
, but you are not supposed to add anything to it. It is a Container
by virtue of being a subclass of Window
. FileDialog
brings up the native “file selection” control, allowing you to choose a file in the file system. A list of files in the current directory is displayed, optionally filtered by some criteria such as “only include files that end in .gif
.”
A FileDialog
can be either a Load dialog, allowing you to select a file for input, or a Save dialog, allowing you to specify a file for output.
What it looks like on screen:
The code to create it:
import java.awt.*; import java.awt.event.*; import java.io.*; public class exfd { public static void main(String args[]) { Frame f = new Frame("myFrame"); final FileDialog fd = new FileDialog(f,"get a GIF file"); fd.show(); fd.setFilenameFilter(new myFilter()); System.out.println("Filter is " + fd.getFilenameFilter() ); String s = fd.getFile(); System.out.println("You chose file "+ s ); } } class myFilter implements FilenameFilter { // broken on Windows public boolean accept(File dir, String name) { return( name.endsWith(".gif") ); } }
The FileDialog
control is only of use in applications and trusted applets because you cannot usually see the client file system in an untrusted applet running in a browser.
A bug in JDK 1.0 and 1.1 (all versions) meant the accept()
method was never called at all on Windows.
Don't forget that most operating systems have case sensitive file names, so foo.gif
is different from foo.GIF
.
To summarize:
Use the javax.swing components in preference to the java.awt components.
The AWT components are shown in this appendix because you might find them in old code or even have to write new code for very old browsers.
Don’t mix old and new events styles. Don’t mix AWT and Swing components.
3.139.81.58