Check out the new USENIX Web site.
Using JavaUSENIX

 

by Rik Farrow
rik@spirit.com

August, 1997

Just when this column was due, the UPS person dropped off a new O'Reilly book. Or rather, the second edition of David Flanagan's Java in a Nutshell. When I taught beginning Java classes, the Nutshell book was my favorite reference and was given to all students. The second edition covers the new features of the 1.1 JDK in the level of detail one expects from a Nutshell book - terse, but useful.

I didn't have time to read the entire book, but I did read through chapter 4, which explains the new features of 1.1. I discovered that I was wrong in my February column - the number of classes more than doubled in 1.1. I might not have counted, but David did. I also learned about reflection, a technique that permits a Java application to examine its own or other classes' methods, arguments, return types, interfaces, and other parts of a class. I had considered writing a Java program that would display this information by reading the class, because I thought it would be useful. Now, a 1.1 package, java.lang.reflect, makes this trivial, and David provides a nice example application.

As in the first edition, Java in a Nutshell is not designed as a standalone tutorial. I like it because it is a great memory aid to one who is getting on in years and likely to forget anything. I also like references that provide lots of examples.

Layout Managers

One thing I didn't find in David's book was any discussion of layout managers. Layout managers handle the placement of components within a Frame or Panel (or any Container). You can handle this yourself, of course, by specifying the move() method (a deprecated 1.0 method), or the 1.1 setLocation() method. After creating an instance of a Button, ScrollBar, or TextField, you can position it absolutely within the container, remembering that the origin is in the upper left corner.

The downsides to absolute positioning are plain. If you have a GUI building tool, layout is not so difficult. Without the tool, graph paper is in order for determining the upper left corner of each component, and its size. The other problem concerns what should happen if the user (can't forget those pesky users) decides to resize the window or chooses a height and width in the applet tag that you didn't plan on?

One approach is simply to coerce the container to a single size and shape. When the user drags the window frame, you capture the event and call resize() to reset the Frame to what you, the programmer, wants. Or call resize() within the applet's init() method for panels within Web pages. These techniques solve the problem of resizing simply by being inflexible.

The other solution is to use one of the five layout managers provided with the JDK, or to write one of your own. Most people choose to use one of the existing layout managers: Flow, Border, Grid, Card, and GridBag. Using layout managers exchanges control over the absolute positioning of components for ease in layout and flexibility.

FlowLayout

FlowLayout is the simplest to use and understand. You add a layout manager to the container you are using. Then, as you add() components, the layout manager handles positioning them. In the case of the FlowLayout, each component is added until the components fill up one row of the container, then the next row is started. You can fill from the left, center, or right. Resizing the container can reduce or increase the number of rows, and the number of components per row.

I wrote a simple application with several variations which allows you to play around with layout managers. In most of these, I simply create five Button objects, using the names of the numbers one through five as labels, with makeButtons(). Let's look at Flow.

import java.awt.*;

public class Flow extends Frame {

public Flow(String name) { 
  super(name); 
  }
public static void main(String args[]) { 
  Flow h = new Flow("FlowLayout test."); 
  Button [] b = new Button[5]; 
  h.makeButtons(b); 
  h.setLayout(new FlowLayout()); 
  for (int i = 0; i < 5; i++) h.add(b[i]); 
  h.resize(200, 100);
  h.show(); 
  }

private void makeButtons(Button[] b) { 
  String [] name = { "One", "Two", "Three",
    "Four", "Five"};
  for (int i = 0; i < b.length; i++) 
     b[i] = new Button(name[i]); 
  } 
}

The Flow class is quite simple. The main() method ignores any arguments and creates a Frame with "FlowLayout test" at the top of the window. The makeButtons() method returns a array of Buttons, and the setLayout() method sets the layout manager for the Frame (the container). Then each Button is added one at a time, the Frame resized, then displayed.

When you run this application, a small window appears, with the first four Buttons in one row, and Button number Five in the second row by itself. Selecting the Button will produce the standard Button behavior, making the borders of the Button invert, producing the appearance of depressing the Button. What is more relevant is to try resizing the window. If you stretch the window to the right, all the Buttons can fit on the first row. If you make the window tall and narrow, each Button has its own row. It is also possible to shrink the window so that only several Buttons appear, still centered.

Several things are happening here. Resizing the window results in the container querying the layout manager for the new position of each of its components. Each component must also be consulted, so that it's preferred size (getPreferredSize() in 1.1) can be determined. Note that the size of the label determines the width of the Buttons (One is narrower than Five), and the font used determines the height. The layout manager, FlowLayout in this example, uses the preferred sizes and the size of the container to position each of the components - if all will still fit.

Border Layout

The BorderLayout manager uses a different scheme for arranging components. There can only be five components, and they may take one of five positions: North, South, East, West, and Center. In these cases, the components are scaled to make the best use of the positions allotted to them. The border positions are long and narrow, and the largest space is given over to the Center. Here is a code fragment from a short application (found on the Web server), for testing the BorderLayout.

public static void main(String args[]) { 
  Border h = new Border("BorderLayout test.");
  Button [] b = new Button[5];
  h.makeButtons(b); 
  h.setLayout(new BorderLayout()); 
  String [] borders = { "North", "East",
     "South", "West", "Center"}; 
  for (int i = 0; i < 5; i++)
     h.add(borders[i], b[i]);
  h.resize(300, 200);
  h.show();
  h.show(); 
}

Components are added using the name of the border for positioning. You might want to experiment by trying to add a sixth component. What happens depends on the version of the JDK which you are using. Note that you can add another container, such as a Panel, instead of a component, then add a row of Buttons to the container. You can also use just two or more positions, say South and Center. This way you could have a large central area with a row of buttons (in the Panel) across the bottom.

Grid Layout

The GridLayout manager permits you to divide the container into equally sized cells. You choose the number of rows and columns when you create the layout manager. Components are added so that they fill up each row, starting at the upper left corner. You can also add spacing, in pixels, between each row and column. To add spacing around the border of any layout manager, you override the insets() method.

public static void main(String args[]) { 
  Grid h = new Grid "GridLayout test."); 
  Button [] b = new Button[5]; 
  h.makeButtons(b);
  h.setLayout(new GridLayout(3, 2, 15, 15)); 
  for (int i = 0;i < 5; i++) h.add(b[i]); 
  h.resize(300, 200); 
  h.show(); 
}

If you run this application, you will notice that each Button has been scaled so that it fills the entire cell. Resizing the window affects the size and shape of the Buttons, although the spacing between the Buttons remains constant.

Suppose you want two rows of Buttons, with an equal amount of space at the bottom of the container. If you allocate twice as many cells as you need, the JDK will delete the extra cells. You cannot use an entire row without components for spacing, as the layout manager simply uses all the available space. You could fill the "unused" cells with Panels, and reserve space by using the Panels.

Another trick you can use with the GridLayout manager is to use nested grids. For example, you could use a top level Grid with just two cells to split a container in half, then add a Panel to one of the cells and use a Grid within that Panel to subdivide it further. Then you have one half of the container as one large cell, and the other as a set of smaller cells.

Other Layout Managers

There are two other layout managers. The CardLayout manager permits you to have many containers, but only one is visible at a time. You use this for the file folder paradigm popular in Windows applications, where each container has a set of tabs on top, with one tab apparently connected to the visible container, and the rest attached to hidden containers.

The GridBagLayout is the most complex layout manager. You have a lot of flexibility here, with the usual price: complexity. You create a GridBagConstraint object, and use it to suggest the position of each component in the container. It's roughly a grid, but one where one cell can steal space from other cells, or take up several cells. You also have control over how components are scaled when the window is resized. I'd like to expand on the folder paradigm, using a CardLayout manager, but will save that for another time.

Terry Slattery of Chesapeake Computer Consulting wrote me about a useful Java applet which you can find at https://www.ccci.com. You can use this applet for calculating subnet numbers and directed broadcast addresses.

As always, I am looking for others who want to exhibit their own Java skills in this space. I think I have one taker now, and am looking for more.

 

?Need help? Use our Contacts page.
Last changed: Jul 24, 1997 jd
Java index
Publications index
USENIX home