A5. AWT Basics


Java provides a library for platform-independent Graphical User Interface (GUI) programming. This library is called the Abstract Windowing Toolkit, or AWT. AWT provides a means to develop a user interface on one platform, and have it run in an equivalent manner on another platform. On each platform, the AWT underpinnings use that platform's native look and feel, abstracting it to the AWT view of the world.

In this section, you will learn:

  • How Java deals with different platforms.
  • How to draw using the Graphics class.
  • How to specify drawing color.
  • How to specify drawing font.
  • How to determine the desktop color scheme.
  • How to display all of the Java graphical user-interface elements (called components).
  • How to lay out components within containers to create GUIs.

Graphical User Interfaces

Most programs need some way to communicate with their users. In the early days of computing, their only input was switches, and their only output lights. While that makes for a good backdrop for a science fiction movie, it isn't the friendliest way to communicate with ther user, and the user had to be an expert to work with them.

Eventually, engineers gave computers more sohpisticated input and output capabilities. Computers could print their information on paper, and read data from pre-punched cards. Still not ideal, but moving in the right direction.

Printer output gave way to Cathode Ray Tubes (CRTs), the precursor to modern monitors. Punch cards were replaced by magnetic tape drives for storage and the card punch keyboards wee connected directly to the computer. Now users could type simple commands on a keyboard and have the results displayed on the CRT in front of them.

But textual commands were considered difficult for non-expert users. Simple textual menus were added to programs to guide the user through tasks. And all the while, some wacky folks at Xerox-parc were playing with graphics and interesting input devices.

User interfaces that were composed of graphical windows, gauges, menus and icons started appearing, and promised a more user-friendly approach to computing. They could now see all the commands available through menus and graphical buttons on the screen. They could set options using buttons, text fields and knobs. The interface became more like physical interfaces they were already used to.

But each platform had its own specific interface. Many Unix workstations use Motif or OpenWindows. PCs primarily use Windows or OS/2. The Macintosh uses its own windowing system. This creates a problem -- if a developer wants to write an application that runs everywhere, they must write different code for the user interface for each platform.

Soon, several GUI portability toolkits appeared, but there were several problems with these:

  • Some only supported a few platforms. The most common ones would create interfaces that could run on Motif and Windows, or Windows and Macintosh.
  • Many were based on C++ as their programming language. Support for C++ on different platforms is wildly inconsistent. So the developer not only had to learn the GUI toolkit, but they had to learn which C++ features were supported on each platform they wanted to use the toolkit on.
  • Many had their own unique look and feel, or borrowed the look and feel of one platform and forced it on all other platforms that use that toolkit. This was unacceptable to users that prefer all applications look & feel the same way on their machine.

OS/2's graphical interface is called the Presentation Manager. While it is similar in design to many other GUI platforms, it has a more "Object-Oriented feel" than any other. IBM designed a graphical toolkit called "OpenClass", a set a libraries for C++ that was fairly portable. When VisualAge for C++ was released, it built on top of OpenClass to help write very nice C++ GUIs. The biggest problem was that VisualAge for C++ had its own set of libraries that were needed to run any GUI that was created using it. The VisualAge libraries were not as portable as OpenClass, meaning that users of VisualAge for C++ that wanted maximum portabilty must directly use the OpenClass libraries and not use VisualAge for C++ to generate their GUIs. VisualAge for Java does not have this problem.

AWT Introduction

Then Java came along. Java provided a common language for all platforms (no inconsistencies like the C++ langauge allowed). And Java provided a common user interface for all platforms. And that interface had the same look & feel as the platform on which it was running. A developer could write a program once and run it on any platform that supports Java (and there are very few that do not.)

The Java language provides a class library called the Abstract Window Toolkit (AWT) that contains a number of common GUI components. These components can be combined to create elaborate user interfaces. The following sections introduce the concepts behind the AWT and how to create simple user interfaces.

AWT Concepts

All graphical user interface (GUI) objects in Java are descendants of the Component class. Components are objects that know how to display themselves (which could include displaying nested components), and how to deal with outside events (such as a mouse click).

A Container is a Component that can hold other Components. Note that because Containers are Components, they can be nested arbitrarily.

A basic user interface using AWT is assembled as follows:

  1. Create an overall component, either a Frame or Applet to act as the ultimate parent container. All other components in the application or applet will reside inside this component. (Note that in same applications you may have several Frames, but a Frame will never be contained in another component.)
  2. Create a component.
  3. Add the component to an existing container.
  4. Prepare the component to respond to events that it sees and cares about.
  5. Rinse and repeat steps 2-4, until you have a full GUI.

We can add components to containers easily, but where do they appear on the screen? You can control where a component will appear and how big it will be:

  • by explicitly telling the components their size and location on the screen.
  • by assigning a layout manager to a container, letting it dictate the size and position of that container's components.

So far, we've said nothing about what the AWT code looks like. This is intentional, as in many cases, GUIs can be created using a tool known as a GUI builder. VisualAge for Java provides a GUI builder known as the "Visual Composition Editor", or VCE. This course concentrates on effectively using the VCE to build graphical applications.

Components

This window shows the available AWT components:

Examples of each of these components are given below, along with the code for that example.

Note that several of these components will also show some C-code snippets for doing similar operations on OS/2. In general, equivalent C code for any graphical java code would require extensive initialization and other GUI setup, and is not presented. Only the most relevant code is shown. Sample OS/2 C code is not provided for all Java examples.

Component Hierarchy

Buttons

A Button widget has a text label and may be "pushed" with a mouse click.

import java.awt.*;
import java.applet.Applet;
public class ButtonTest extends Applet {
  public void init() {
    Button b = new Button("OK");
    add(b);
  }
}

Creating an OS/2 button (in C) is a bit more involved. You need to manage all the details for the button explicitly. Another thing to notice -- buttons in OS/2 are windows! They have a "PUSHBUTTON" style so they look and act like a button. To associate them with the parent window, we just make the parent window its' parent.

HWND hwnd =
    WinCreateWindow(
            hwndParent,     /* Parent window */
            WC_BUTTON,      /* Window class */
            Caption,        /* Window text */
            WS_VISIBLE |    /* Button Style */
            BS_PUSHBUTTON |
            BS_AUTOSIZE,
            Xpos,           /* x position */
            Ypos,           /* y position */
            width,          /* Width */
            height,         /* Height */
            hwndParent,     /* Owner window */
            HWND_TOP,       /* Top of z-order */
            wndID,          /* Window identifier */
            NULL,           /* Control data */
            NULL);          /* Presentation parameters */

There is no direct support for images as Button labels. However, an ImageButton can be easily created by subclassing java.awt.Button and overriding its paint() method. This is left as an exercise for the interested student.

Canvas

A Canvas is a graphical component representing a region where you can draw things such as rectangles, circles, and text strings. You subclass Canvas to override the default Canvas.paint() method.

import java.awt.*;
import java.applet.Applet;
public class CanvasPaintTest extends Applet {
  public void init() {
    DrawingRegion region = new DrawingRegion();
    add(region);
  }
}

class DrawingRegion extends Canvas {
  public DrawingRegion() { resize(100,100);}
  public void paint(Graphics g) {
    g.drawRect(0,0,99,99); // draw border
    g.drawString("A Canvas", 20,20);
  }
}

Painting in OS/2 C is very similar, with the exception of lots of initialization code that is not shown here.

hps = WinBeginPaint( hwnd, 0L, &rc );       /* start painting   */
WinFillRect( hps, &rc, SYSCLR_WINDOW);      /* clear the window */
static POINTL startBox;                     /* define the start and end corners
                                                of the box */
startBox.x = 0;
startBox.y = 0;
static POINTL endBox;
endBox.x = 99;
endBox.y = 99;
GpiSetCurrentPosition(hps, &startBox);      /* start point of rectangle
GpiSetColor( hps, CLR_NEUTRAL );            /* rectangle line color     */
GpiSetBackColor( hps, CLR_BACKGROUND );     /* its background and       */
GpiSetBackMix( hps, BM_OVERPAINT );         /*   how it mixes           */
GpiBox( hps, DRO_OUTLINE, &endBox, 0, 0);   /* draw the box             */
WinEndPaint( hps );                         /* Drawing is complete      */

The Canvas class is frequently subclassed to create new component types. However, starting with Java 1.1, you can subclass Component directly to create "lightweight", transparent widgets.

Checkbox

A Checkbox is a label with a small pushbutton. The state of a Checkbox is either true (button is checked) or false (button not checked). The default initial state is false. Clicking on a Checkbox toggles the state. For example:

import java.awt.*;
import java.applet.Applet;
public class CheckboxSimpleTest extends Applet {
  public void init() {
    Checkbox m = new Checkbox("Allow Mixed Case");
    add(m);
  }
}

To set a Checkbox initially true use a null CheckboxGroup with an alternate constructor:

Checkbox cb = new Checkbox("Label", null, true);

With Java 1.1, there is another alternative, without a CheckboxGroup

Checkbox cb = new Checkbox("Label", true);

In C on OS/2, code to create a checkboxes might look like:

HWND hwnd =
    WinCreateWindow(
        hwndParent,             /* Parent window */
        WC_BUTTON,              /* Window class */
        Caption,                /* Window text */
        WS_VISIBLE |            /* make the window a checkbox */
        BS_AUTORADIOBUTTON,     /* Button style */
        Xpos,                   /* x position */
        Ypos,                   /* y position */
        width,                  /* Width */
        height,                 /* Height */
        hwndParent,             /* Owner window */
        HWND_TOP,               /* Top of z-order */
        wndID,                  /* Window identifier */
        NULL,                   /* Control data */
        NULL);                  /* Presentation parameters */

CheckboxGroup

A CheckboxGroup is used to control the behavior of a group of Checkbox objects (each of which has state true or false). Exactly one of the Checkbox objects is allowed to be true at one time. Checkbox objects controlled with a CheckboxGroup are sometimes called "radio" buttons.

The following example illustrates the basic idea behind radio buttons.

import java.awt.*;
import java.applet.Applet;
public class CheckboxGroupTest extends Applet {
  public void init() {
    // create button controller
    CheckboxGroup cbg = new CheckboxGroup();
    Checkbox cb1 = new Checkbox("Show lowercase only", cbg, true);
    Checkbox cb2 = new Checkbox("Show uppercase only", cbg, false);
    add(cb1);
    add(cb2);
  }
}

For most applets, however, Checkbox will have to be subclassed to provide specific behavior.

Choice

Choice objects are drop-down lists. The visible label of the Choice object is the currently-selected entry of the Choice.

import java.awt.*;
import java.applet.Applet;
public class ChoiceSimpleTest extends Applet {
  public void init() {
    Choice rgb = new Choice();
    rgb.addItem("Red");
    rgb.addItem("Green");
    rgb.addItem("Blue");
    add(rgb);
  }
}

The first item added is the initial value set for the Choice object. Also, with Java 1.1, you can use the add() method instead of addItem().

A simple choice list on OS/2 might look like:

hwndComboBox = WinCreateWindow(hwnd,    /* Parent */
        WC_COMBOBOX,                    /* Class */
        "",                             /* Name */
        WS_VISIBLE | LS_NOADJUSTPOS,    /* Style */
        10, 10,                         /* x, y */
        110, 200,                       /* cx, cy */
        hwnd,                           /* Owner */
        HWND_TOP,                       /* Behind */
        ID_LISTWINDOW,                  /* ID */
        NULL,                           /* Control data */
        NULL);                          /* parameters */
      /* Disable updates while filling the list. */
      WinEnableWindowUpdate(hwndComboBox, FALSE);
      WinInsertLboxItem(hwndComboBox, 0, "Red"); 
      WinInsertLboxItem(hwndComboBox, 0, "Green"); 
      WinInsertLboxItem(hwndComboBox, 0, "Blue"); 

Label

A Label is a displayed String object.

import java.awt.*;
import java.applet.Applet;
public class LabelTest extends Applet {
  public void init() {
    add(new Label("A label"));
    // right justify next label
    add(new Label("Another label", Label.RIGHT));
  }
}

Labels are restricted to a single line of text.

Creating a similar label in OS/2 looks like:

hwndStatic2 = WinCreateWindow(
    hwnd,           /* Parent window */
    WC_STATIC,      /* Window class */
    "A label",      /* Window text */
    WS_VISIBLE |    /* Make it visible */
    SS_TEXT    |    /* Static-text control */
    DT_VCENTER |    /* Center text vert. */
    DT_RIGHT,       /* Right Justify horiz. */
    20,             /* x position */
    170,            /* y position */
    75,             /* Width */
    20,             /* Height */
    hwnd,           /* Owner window */
    HWND_TOP,       /* Top of z-order */
    ID_STATIC2,     /* Window identifier */
    NULL,           /* Control data */
    NULL);          /* Presentation parameters */

List

A List is a scrolling list box that allows you to select one or more items.

Multiple selections may be used by passing true as the second argument to the constructor.

import java.awt.*;
import java.applet.Applet;
public class ListSimpleTest extends Applet {
  public void init() {
    String[] items = {"Seattle", "Washington",
                      "New York", "Chicago",
                      "Miami","San Jose",
                      "Denver" };
    List list = new List(5, false);
    for (int i=0; i<items.length; i++) {
      list.addItem(items[i]);
    }
    add(list);
  }
}

The constructor may contain a suggested # of lines to display. However, a layout manager may change this, based upon available space. Also, with Java 1.1, you can use the add() method instead of addItem().

An OS/2 list is a window that is of type LISTBOX:

hwndListBox1 = WinCreateWindow(
    hwnd,           /* Parent window */
    WC_LISTBOX,     /* Window class */
    "",             /* Window text */
    WS_VISIBLE |    /* Make it visible */
    LS_NOADJUSTPOS, /* List Box Options */
    20,             /* position */
    20,             /* y position */
    400,            /* Width */
    300,            /* Height */
    hwnd,           /* Owner window */
    HWND_TOP,       /* Top of z-order */
    ID_LISTBOX1,    /* Window identifier */
    NULL,           /* Control data */
    NULL);          /* Presentation parameters */

Scrollbar

A Scrollbar is a "slider" component with characteristics specified by integer values that are set during Scrollbar construction. Both horizontal and vertical scroll bars are available.

import java.awt.*;
import java.applet.Applet;
// A simple example that makes a Scrollbar appear
public class ScrollbarSimpleTest extends Applet {
  public void init() {
    Scrollbar sb = new 
    Scrollbar(Scrollbar.HORIZONTAL,
      0, // initial value is 0
      5, // width of slider
      -100,100); // range is [-100,100]
    add(sb);
  }
}

TextField

A TextField is a scrollable (meaning the text scrolls as you move the cursor) text display object with one row of characters. The width of field is specified during construction and an initial string may be specified.

import java.awt.*;
import java.applet.Applet;
public class TextFieldSimpleTest extends Applet {
  public void init() {
    TextField f1 = new TextField("type something");
    add(f1);
  }
}

Pointers:

  • setEditable(true) for read-only

  • The constructor has optional width parameter.
    This does not control # of characters in TextField, only visible width on screen.

  • For password fields:
    setEchoCharacter('?'); [Java 1.0]
    setEchoChar('?');      [Java 1.1]
    
    to clear/reset:
    setEchoCharacter((char)0); [Java 1.0]
    setEchoChar((char)0);      [Java 1.1]
    

TextArea

A TextArea is a multi-row text field that displays a single string of characters, where newline ('\n') ends each row. The width and height of the field is set at construction, but the text can be scrolled up/down and left/right. There is a 32 KiloByte memory limit on most implementations of TextArea, so you may not want to use it for large text displays.

import java.awt.*;
import java.applet.Applet;
public class TextAreaSimpleTest extends Applet {
  TextArea disp;
  public void init() {
    disp = new TextArea("Code goes here", 10, 30);
    add(disp);
  }
}

There is no way to put the cursor at the beginning of row 5, only to say put cursor at a single dimension position 50. Also, in Java 1.0.x, there is no control over when scrollbars appear.

Mapping Java Components to the Openclass Library

The following table shows some of the relationships between the IBM OpenClass libraries and Java Components. It is provided here as a frame of reference for those who are familiar with the OpenClass libraries.

Windowing Classes
Basic Windowing App. IFrameWindow Frame
Document Component Applet
Dialog Box IFrameWindow Dialog
Frameless Window ICanvas Panel
File Dialog IFileDialog FileDialog
 
 
Geometry Management Classes
Basic Subwindow ICanvas Panel
Split window ISplitCanvas GridLayout, GridBagLayout
Regularly spaced grids ISetCanvas GridLayout
Scrolling larger windows IViewPort ScrollPane
Irregular rows and columns IMultiCellCanvas GridBagLayout
Multiple exclusive pages INotebook CardLayout, Buttons

Note: The Geometry Management Classes accomplish similar tasks in ways that are often quite different from each other. Comparisons are loose equivalence only.
 
Menu Classes
Frame Window Menu IMenuBar MenuBar
Menu Item  IMenuItem MenuItem
Menu Event IMenuEvent ActionEvent
Popup Menu IPopupMenu PopupMenu
Menu Event Handler IMenuHandler ActionListener
 
 
Control Classes
Text Label IStaticText Label
Entry Field IEntryField TextField
Push Button IPushButton Button
Check Box ICheckBox CheckBox
Radio Button IRadioButton CheckBox, CheckBoxGroup
Memo Field IMultiLineEdit TextArea
List Box IListBox List
Combo Box IComboBox Choice
Group Box IGroupBox Taligent BorderPanel Widget
Scroll Bar IScrollBar ScrollBar

Note: For the control classes, these are some of the most common. They are very similar in many cases, and most communicate by sending events (though the type of events is different) to some kind of handler (listener).
 
 

Platform Specific Information

There are cases where some platform information is necessary, but should still be obtained in a platform-independent manner. Java provides an abstract class called Toolkit that provides an interface to platform specific details such as the list of system fonts and screen size. The currently-active toolkit may be obtained via:

Toolkit tk = Toolkit.getDefaultToolkit(); 

The list of system fonts can be obtained via:

String s[] = tk.getFontList();

The toolkit takes care of translating the font name to a native font. The Toolkit class can also be used to get the size of the screen:

Dimension d = tk.getScreenSize();

This information can be used to position/size windows.

Graphics Primitives

Java draws text and shapes using the Graphics class, which provides a graphics "context" on components such as applets, images and canvases. You can draw the following shapes:

Lines

public void paint(Graphics g) {
  g.drawLine(10, 10, 20, 30);
}

All lines are one pixel wide, with no support for fill patterns (i.e., dashed/dotted lines).

drawLine() is the only shape drawing routine that uses two points for its parameters. All the remaining shape drawing routines use a bounding rectangle, using the point at the top left corner along with parameters for width and height.

Rectangles

public void paint(Graphics g) {
  g.setColor (Color.black);
  g.drawRect (25, 10, 50, 75);
  g.fillRect (25, 110, 50, 75);
  g.drawRoundRect (100, 10, 50, 75, 60, 50);
  g.fillRoundRect (100, 110, 50, 75, 60, 50);
  g.setColor (Color.gray);
  g.draw3DRect (175, 10, 50, 75, true);
  g.draw3DRect (175, 110, 50, 75, false);
  g.fill3DRect (250, 10, 50, 75, true);
  g.fill3DRect (250, 110, 50, 75, false);
}

3-D rectangles must not be black for perspective to show.

Arcs

public void paint(Graphics g) {
  g.drawArc (25, 10, 50, 75, 0, 360);
  g.fillArc (25, 110, 50, 75, 0, 360);
  g.drawArc (100, 10, 50, 75, 45, 215);
  g.fillArc (100, 110, 50, 75, 45, 215);
  g.drawOval (175, 10, 50, 75);
  g.fillOval (175, 110, 50, 75);
  g.drawOval (250, 10, 50, 50);
  g.fillOval (250, 110, 50, 50);
}

Notice fillArc() fills arcs like pie-chart pieces, not end-point to end-point.

The point provided is the top left corner of the bounding rectangle of the arc/oval, not the center point.

To draw a circle, the width and height need to be equal.

Polygons

public void paint (Graphics g) {
  for (int i=0;i<nPoints;i++) {
    xPoints[i] = (int)(Math.random()* size().width);
    yPoints[i] = (int)(Math.random()* size().height);
  }
  p = new Polygon(xPoints, yPoints, nPoints);
  g.drawPolygon (p);
  Rectangle r = p.getBoundingBox();
  g.drawRect (r.x, r.y, r.width, r.height);
}

You can use fillPolygon() instead of drawPolygon(). In Java 1.0.x, drawPolygon() does not connect the first and last points. If these two points not the same, then the result is an open polygon. In Java 1.1.x, drawPolygon() does connect the first and last points. If you don't want them to be connected, there is the drawPolyline() method.

Painting

While drawing, you can set either paint mode or XOR mode. Paint mode, setPaintMode(), is the normal mode of drawing--the bits are turned on in the current color as drawing proceeds. XOR mode, setXORMode(xorColor), in contrast, is used to draw over existing bits in such a way that if the same shape is drawn again (in the same color), the graphics area is restored. In other words, drawing once in XOR mode draws your shape--drawing it again erases it. While drawing, the color of each pixel is the exclusive-or (XOR) of the old color, the drawing color, and the xor color.

color = xorColor ^ bgColor ^ drawColor;

In practice, the background color is used as the xor color.

Example:

import java.awt.*;
public class xor extends java.applet.Applet {
  public void init () {
    setBackground (Color.yellow);
  }
  public void paint (Graphics g) {
    g.setColor (Color.magenta);
    g.setXORMode (Color.pink);
    g.fillRect (10, 10, 100, 100);
    g.fillRect (35, 60, 50, 100);
  }
}

Drawing Text

Text may also be drawn on a graphics context via:

g.drawString("string", x, y);

The x,y location indicates where the left-edge and baseline of the first character should go--descending characters such as 'p' will have portions below the y coordinate. Note that the y value is not the top line of the text to be drawn. See FontMetrics for information that will help determine the baseline's value.

Magercise

  • 1. Drawing a stick figure.
  • Colors

    The current foreground and background color may be set when drawing. Many colors have predefined names; here are the predefined colors of the Color class: Color.black, Color.blue, Color.cyan, Color.darkGray, Color.gray, Color.green, Color.lightGray, Color.magenta, Color.orange, Color.pink, Color.red, Color.white, Color.yellow.

    The following code demonstrates the basics of setting the current drawing color. It turns the entire applet window blue and draws a string in red.

    import java.awt.*;
    public class rb extends java.applet.Applet {
      public void init () {
        setForeground (Color.red);
        setBackground (Color.blue);
      }
      public void paint (Graphics g) {
        g.drawString ("Help Me", 50, 50);
      }
    }
    

    If color not a known name to Java, can always provide red, green, and blue (RGB) components or hue, saturation, and brightness (HSB):

    // Both are Aquamarine
    Color c1 = new Color (127, 255, 212);
    Color c2 = Color.getHSBColor (.444f, .502f, 1.0f);
    

    Make sure that the screen gets redrawn (via repaint() or some other mechanism) after changing colors; there will be no effect until the redraw occurs.

    Magercise

  • 2. Colored Panes.
  • Fonts

    When drawing text, the current Font dictates the size, shape, and spacing. Method setFont() is used to set the current font for graphics contexts and components. For example, to draw "hello" in a bold Helvetica font, at 16 point, the following is sufficient:

    public void paint(Graphics g) {
      Font f = new Font("Helvetica", 
        Font.BOLD, 16);
      g.setFont(f);
      g.drawString("hello", 10, 20);
    }
    

    The other possible modifiers are:

    • Font.PLAIN
    • Font.BOLD
    • Font.ITALIC
    • Font.BOLD | Font.ITALIC

    Note: there is no underline characteristic.

    Due to trademark and internationalization issues, the font names changed in version 1.1. The original font names are still available, however there are new names that you should use:

    • TimesRoman is now Serif
    • Helvetica is now SansSerif
    • Courier is now Monospaced
    • Dialog and DialogInput are still available
    • ZapfDingbats is no longer necessary since characters in font have official Unicode mappings in the range \u2700 to \u27ff.

    Magercise

  • 3. Font list.
  • Font Metrics

    To get platform-specific font-size information, ask the toolkit for the font metrics:

    Font f = new Font("Serif", Font.BOLD, 16);
    Toolkit t = Toolkit.getDefaultToolkit();
    FontMetrics fm = t.getFontMetrics(f);
    

    You can also ask the graphics context for the current font metrics:

    g.getFontMetrics ();
    

    A FontMetrics object contains (among other things) for each font:

    • Height values for font. This is the amount of space needed from one baseline to the next. (This is the sum of the leading, ascent and descent).
    • Leading (space between lines). This is the amount of space between the descent of a line, and the ascent of the next line.
    • Ascent (space above baseline for characters). This is the amount of space above the baseline that the tallest character in the font requires.
    • Descent (space below baseline for characters). This is the amount of space below the baseline that characters like "g", "p" and "y" require for their descenders.
    • Advance width of a specific character.
    • Advance width of a string of characters.

    Advance width is width of character plus inter-character space. Allows you to position NEXT character properly after string.

    The following example draws an underlined string by drawing a line the width of the string at the same y position as the string:

    import java.awt.*;
    public class rbfm extends java.applet.Applet {
      public void init () {
        setForeground(Color.red);
        setBackground(Color.blue);
        setFont(new Font("TimesRoman", Font.BOLD, 24));
      }
      public void paint(Graphics g) {
        FontMetrics fm = g.getFontMetrics();
        // We want the text line to start at y=50.  To do this,
        //   we need to drop down by the leading amount to give breathing
        //   room, then drop down by the ascent amount.
        int baseline = 50 + fm.getLeading() + fm.getHeight();
        g.drawString("Hi Mom", 50, baseline);
        int sWidth = fm.stringWidth("Hi Froggy!");
        g.drawLine(50, baseline, 50+sWidth, baseline);
      }
    }
    

    System Colors

    Java 1.1 introduces the SystemColor class to provide access to the current desktop color scheme. If you are trying to draw something on the screen to appear similar to a system object, you can ask the system what color to use and it will provide you with an appropriate Color object. There are 25 different constants that provide colors for anything from frame borders, to text colors, to menu colors. This is useful when drawing things like GUI widgets.

    The following demonstrates how to use these constants to draw a three dimensional button. It will NOT work in Java 1.0 browsers like Netscape Navigator 3.0 and Internet Explorer 3.0.

        
    public synchronized void paint (Graphics g) {
      FontMetrics fm = g.getFontMetrics();
      Dimension size=getSize();
      int x = (size.width - fm.stringWidth(text))/2;
      int y = (size.height + fm.getHeight())/2;
      g.setColor (SystemColor.control);
      g.fillRect (0, 0, size.width, size.height);
      if (state)
        g.setColor (SystemColor.controlShadow);
      else
        g.setColor (SystemColor.controlDkShadow);
      g.drawLine (0, 0, 0, size.height-1);
      g.drawLine (0, 0, size.width-1, 0);
      if (state)
        g.setColor (SystemColor.controlDkShadow);
      else
        g.setColor (SystemColor.controlShadow);
      g.drawLine (0, size.height-1, size.width-1,
          size.height-1);
      g.drawLine (size.width-1, 0, size.width-1,
          size.height-1);
      g.setColor (SystemColor.controlText);
      g.drawString (text, x, y);
    }
    

    Containers

    Containers (class java.awt.Container) are AWT components that can contain other AWT components. This section will discuss two key conceptual aspects of an AWT container.

    Insets

    Every container defines a set of spacing amounts called Insets. Insets tell a container's layout manager how much room is reserved around the inside of that container's border. This information is usually directly related to drawing operations performed by the container in its paint() method. Look at the following example applet. It defines a subclass of Panel called BoxedPanel that draws a rectangular box around anything contained in that panel. If the BoxedPanel had not defined its insets, there would be no way for its layout manager to know that the BoxedPanel was reserving space, and it would position the contained components over the drawn box.

    import java.awt.*;
    
    public class BoxedPanel extends Panel {
      Color color;
      public BoxedPanel() {
        this(Color.black);
      }
      public BoxedPanel(Color c) {
        color = c;
      }
      public Insets insets() {
        return new Insets(5,5,5,5);
      }
      public void paint(Graphics g) {
        g.setColor(color);
        g.drawRect(2, 2, size().width-5,
          size().height-5);
      }
    }
    
    import java.awt.*;
    import java.applet.Applet;
    
    public class Testbox extends Applet {
      public void init() {
        Panel p1 = new BoxedPanel();
        Panel p2 = new BoxedPanel(Color.red);
        p1.add(new Button("First"));
        p1.add(new Button("Second"));
        add(p1);
        p2.add(new Button("Third"));
        p2.add(new Button("Fourth"));
        add(p2);
      }
    }
    

    Adding Components to a Container

    Containers define an add method which is used to make the container a parent for some other AWT component. The add method can come in two forms:

    • add(component) -- just adds the component to the container's component list. Whenever the container is repainted, any contained components that need to be repainted will be.
    • add(constraint, component) -- adds the component to the container's component list, but also passes the constraint information to the container's layout manager (if one has been assigned.) More on this later.

    Components can be removed with a corresponding remove method call.

    Layout Managers

    Now we have enough groundwork laid to talk about layout managers.

    Many early GUI applications were developed for screen resolutions of around 320x200 pixels. Developers crafted their GUIs to fit nicely in this resolution and they looked and acted very nicely. But, as time progressed, screen resolutions improved. Jumps in resolution to 640x400 or other sizes soon appeared. When users executed the old applications, they appeared to cover one quarter of the screen, and looked a bit odd.

    The situation got worse when operating systems displayed these GUIs in their own window, and allowed that window to be resized. The users could resize the window, but the GUI only covered the top/left quarter of these windows.

    This annoyed many users. "What can't I see the whole screen when I change the size?" "Why won't the fields get bigger?" This was especially problematic for tools that managed to present GUIs on different platforms, as each platform defined different screen resolutions. You could even have an application appear to be "chopped off" if the new screen resolution was smaller than that used by the application.

    Some clever programmers decided to program these actions themselves -- they would watch for an event that told them a window was being resized, then explicitly compute the new sizes of the components that they wanted to resize. But this was not done often, as it involved quite a bit of code.

    Then along came a remarkable idea, long before Java was even known as "Oak." What if the window had a separate object look at it's current size and what components are contained within it, and figure out the best size and position for those components? The concept of a layout manager had been born.

    Several small languages adopted the idea. But none really made the idea stand out as much as Java.

    Every Container has a layout manager reference. If this reference is null, we get the old behavior of "every component for itself." All components have fixed size and position, unless your program explicitly changes them.

    If that layout managers reference is not null, the LayoutManager object to which it refers will perform the "look and size/position" operation mentioned above. If one of the resized components happens to be a container and has a layout manager associated with it, that layout manager will be invoked to lay out that container's components. This creates a highly flexible means of allowing a GUI to use all the space granted it in a very effective way.

    In Java's AWT, there are a variety of pre-defined layout manager objects to handle different situations. For example, when placing the keys of an on-screen calculator, a manager that lays things out in a grid would be most suitable. If one of the predefined layout managers doesn't handle the task, you can either nest panels with different layout managers, or create a new layout manager entirely. (And they are fairly simple to implement, but beyond the scope of this course.)

    Because different regions of a GUI are most conveniently laid out in different ways, the Java language allows regions to be broken up into smaller regions, each having its own layout manager. For example, consider modeling a cellular phone. The phone has a keypad and an LCD display. The keypad is obviously a grid-type layout, but the display contains a bar graph of the signal strength, battery strength and volume, as well as the phone number you are dialing. The cellular phone display might therefore be modeled with two separate layout regions, one for the keypad and one for the display).

    The following sections describe the simplest layout managers in the Java AWT.

    FlowLayout

    A FlowLayout arranges components left-to-right until no more objects fit on that "line". Any further objects added will wrap to the next line. By default, each line in the flow layout will be centered. This behavior can be changed by passing FlowLayout.LEFT or FlowLayout.RIGHT to the constructor of the FlowLayout object. FlowLayout is the default layout manager associated with Panel and, therefore, of Applet.

          
    import java.awt.*;
    import java.applet.Applet;
    public class FlowLayoutTest extends Applet {
      public void init() {
        setLayout(new FlowLayout());	// default
        add(new Button("B1"));
        add(new Button("B2"));
        add(new Button("B3"));
      }
    }
    
    FlowLayout does NOT resize its components.
    BorderLayout

    The BorderLayout manager has "North", "East", "South", "West", and "Center" positions where you may place components. The "North", "East", "South", "West" components are placed around the edge of the container, immediately inside its insets, and the "Center" component takes up the left-over space in the middle. The components are automatically resized when the area of the layout is changed.

    import java.awt.*;
    import java.applet.Applet;
    public class BorderLayoutTest extends Applet {
      public void init() {
        setLayout(new BorderLayout());
        add("North",  new Label("A Header Maybe"));
        add("South",  new TextField("Type some text here"));
        add("West",   new Button("QUIT"));
        add("East",   new Button("HELP"));
        add("Center", new TextArea("Some random text\nin a TextArea"));
      }
    }
    

    BorderLayout is the default LayoutManager for Window, Dialog, and Frame.

    Note: When adding components to a container in Java 1.1, you should swap the parameters to add such that the constraints are second. Through the new LayoutManager2 interface, constraints are now the second parameter to add and are not limited to text strings. Also, instead of using "North", "South", "East", "West", and "Center", there are class constants for the different regions:

    • BorderLayout.NORTH
    • BorderLayout.SOUTH
    • BorderLayout.EAST
    • BorderLayout.WEST
    • BorderLayout.CENTER

    So, to add Component comp to the center region use:

    add (comp, BorderLayout.CENTER);
    

    Magercise

  • 4. Compass Points.
  • GridLayout

    The GridLayout manager arranges components into rows and columns. You fill the grid row-by-row with graphical components. For example, the first element to be added to a 3 row x 2 column grid will be the first element of the first row. The third element to be added to a 3x2 grid will be the first element of the second row.

    import java.awt.*;
    import java.applet.Applet;
    public class GridLayoutTest extends Applet {
      public void init() {
        setLayout(new GridLayout(3, 2));
        add(new Button("1")); // upper-left button
        add(new Button("2"));
        add(new Button("3"));
        add(new Button("4"));
        add(new Button("5"));
        add(new Button("6")); // lower-right button
      }
    }
    

    The size passed to GridLayout constructor is only a suggested size. The LayoutManager can change this if the number of components isn't the maximum. Also, either parameter may be zero to grow without bounds. The following example creates a single column of 5 buttons:

    setLayout(new GridLayout(0, 1));
    for (int i=0;i<5;i++)
      add(new Button(""+i));
    

    Every object in the Container will be the same size.

    Magercise

  • 5. Phone Dialing Keypad.
  • CardLayout

    The CardLayout manager displays only one component at a time. Each Component "card" fills the area of the entire container. The cards are referred to by a programmer-defined string that is stored in a Hashtable by CardLayout. Cards may be "brought to the front" by calling method show() with the string for the card's name.

    import java.awt.*;
    import java.applet.Applet;
    public class CardLayoutSimpleTest extends Applet {
      CardLayout layout;
      Panel p1 = new BoxedPanel();
      Choice c = new Choice();
      public void init() 	{
        layout = new CardLayout();
        p1.setLayout(layout);
        p1.add("Bob",  new Label("A description of  Bob"));
        p1.add("Jane", new Label("A description of Jane"));
        add(p1);
        c.addItem("Bob");
        c.addItem("Jane");
        add(c);
      }
      public boolean action(Event e, Object o) {
        if (e.target == c) {
          layout.show(p1, o.toString());
          return true;
        }
        return false;
      }
    }
    

    Normally, there is an object or objects outside the CardLayout panel used to jump to other cards. Currently, there is no built-in object to provide the familiar tabbed dialog interface. In addition to show("cardname"), you can also use next() and previous() methods of CardLayout to flip around.

    Magercise

  • 6. Flipping through components.
  • 7. A Four-Function Calculator (part one).
  • 8. Absolute Layout.
  • ScrollPane

    The ScrollPane container was introduced in Java 1.1 to provide a new Container with automatic scrolling of any ONE large Component. That large object could be anything from an image that is too big for the display area to a bunch of spreadsheet cells. All the event handling mechanisms for scrolling are managed for you. Also, there is no LayoutManager for a ScrollPane since there is only a single object within it, and that object is larger than the screen size. (Remember, the intent of layout managers is to look at the size of their container and arrange the container's components within that space.)

    The following example demonstrates the scrolling of a large Image:

    import java.awt.*;
    import java.applet.*;
    
    class ImageCanvas extends Canvas {
      Image image;
      public ImageCanvas (Image i) {
        image = i;
      }
      public void paint (Graphics g) {
        if (image != null)
          g.drawImage (image, 0, 0, this);
      }
    }
    
    public class ScrollingImage extends Applet {
      public void init () {
        setLayout (new BorderLayout());
        ScrollPane sp = new 
          ScrollPane(ScrollPane.SCROLLBARS_ALWAYS);
        Image im = getImage (
          getDocumentBase(), "SMarea.gif");
        sp.add (new ImageCanvas (im));
        add (sp, "Center");
      }
    }
    

    If you happen to be running a 1.1 browser, you can test it, or just examine the source.


    Copyright © 1996-1997 MageLang Institute. All Rights Reserved.