Appendix B. Obsolete Components of the Abstract Window Toolkit

Obsolete Components of the Abstract Window Toolkit

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.

How the Java Abstract Window Toolkit Works

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.

How the Java abstract window toolkit works.

Figure B-1. How the Java abstract window toolkit works.

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.

Controls, Containers, Events

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 most important of the AWT classes.

Figure B-2. The most important of the AWT classes.

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.

Overview of Controls

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!

All About AWT Controls (Components)

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.

The controls (visible AWT objects) of Java.

Figure B-3. The controls (visible AWT objects) of Java.

The controls (visible AWT objects) of Java.

These classes are the controls or building blocks from which you will create your GUI. What you do with all these components is:

  1. Add them to a container (usually Frame or Applet), then display the container with the show() method.

  2. 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.

Button

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:

Button

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).

Button

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.)

Canvas

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:

Canvas

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:

Canvas

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 

Adapter Classes

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.

Checkbox

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:

Checkbox

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.

CheckboxGroup

What it is: There is a way to group a series of checkboxes to create a CheckboxGroup 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:

CheckboxGroup

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.

Choice

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:

Choice

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:

Choice

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.

Label

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:

Label

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.

List

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:

List

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(); 

Scrollbar

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:

Scrollbar

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.

TextField

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:

TextField

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.

TextField

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).

TextArea

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:

TextArea

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.

Menus: Design

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 terminology of menus.

Figure B-4. The terminology of menus.

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.

Menu : Class

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:

Menu : Class

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.

CheckboxMenuItem

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:

CheckboxMenuItem

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());
     }
} 

Pop-up Menus

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:

Pop-up Menus

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
     }
} 

All About Containers

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.

Class hierarchy of containers.

Figure B-5. Class hierarchy of containers.

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.

ScrollPane

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:

ScrollPane

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);}
} 

Window

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:

Window

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.

Frame

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:

Frame

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:

Frame

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.

Panel

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:

Panel

Applet

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.

Just another applet.

Figure B-6. Just another 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

Dialog

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:

Dialog

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();
     }
} 

FileDialog

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:

FileDialog

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:

  1. Use the javax.swing components in preference to the java.awt components.

  2. 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.

  3. Don’t mix old and new events styles. Don’t mix AWT and Swing components.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.81.58