Layout Managers                                                                                    Peter Komisar
                                                                                                                latest revision April 23, 2001

references: the JDK 1.2.2 API documentation,  Java Certification Study Guide, Heller & Roberts.
'Core Java', Horstmann and Cornell, Java 2, Developer's Handbook, Heller & Roberts


Java uses a group of layout managers which when used in combination can create practically
any layout of visual components.The three commonest are BorderLayout, FlowLayout, and
GridLayout from the awt package.. Harder to use but more versatile is GridBagLayout.
GridBagLayout allows components to occupy different amounts of space relative to it's
adjacent components on the user interface. GridBagLayout also permits locating objects
with x-y grid positions. It is purported to be the manager often used in 'behind the scenes'
in  commercial IDEs and visual GUI builders.

No LayoutManager

You can set a containers layout to null creating the situation where no layout manager is active,
 /* setLayout(null) */ . This will lead to calls like setSize( ) and setBounds( ) actually working
and not being overridden by the layout manager's policy. The responsibility for positioning
components falls onto the programmer, including whenever the container is resized.This requires
overriding the container's setBounds( ) method.( setSize( ) calls setBounds( ) ). In order for
setBounds to work when resizing, you have to provide a layout policy for setBounds. Easier
than doing this is to do a custom layout where resizing is taken care of for you.
 
 
 An example of a swing frame set to a null layout


class NoLayout extends JFrame{
  NoLayout(String s){
    super(s);
    JPanel panel=new JPanel();
    panel.setLayout(null);                           // here's a panel's layout being set to null
    JLabel label= new JLabel("A Label");
    label.setBounds(40,20,120,20);     // here is a component having it's bounds being set
    panel.add(label);
    JTextField text=new JTextField("A loaded textfield"); 
    text.setBounds(40,70,120,20);
    panel.add(text);
    JTextArea textArea=new JTextArea(" Some text \n in a text area");
    textArea.setBounds(40,120, 120, 50);
    panel.add(textArea);
    getContentPane().add(panel,BorderLayout.CENTER);
    setSize(250,250);
    setVisible(true);
    }
public static void main(String[]args){
    new NoLayout("A frame set to a null layout");
    }
  }

 // the convenience of a null layout is fine grained control of a layout. 
 // The downside is this layout doesn't resize 

Custom Layout Managers

You can experiment creating your own layout managers by implementing the five methods
of the LayoutManager interface or the ten methods of the LayoutManager2 interface.
Otherwise, you can use one of the following stock layout managers.
 

BorderLayout   // from the JDK API

A border layout lays out a container, arranging and resizing its components to fit in five regions:
north, south, east, west, and center. Each region is identified by a corresponding constant:
NORTH, SOUTH, EAST, WEST, and CENTER. When adding a component to a container
with a border layout, use one of these five constants, for example:

    Panel p = new Panel();
    p.setLayout(new BorderLayout( ));
    p.add(new Button("Okay"), BorderLayout.SOUTH);

BorderLayout interprets the absence of a string specification the same as the constant CENTER:

    Panel p2 = new Panel( );
    p2.setLayout(new BorderLayout());
    p2.add(new TextArea());  // Same as p.add(new TextArea(), BorderLayout.CENTER);
 

In addition, BorderLayout supports four relative positioning constants, BEFORE_FIRST_LINE,
AFTER_LAST_LINE, BEFORE_LINE_BEGINS, and AFTER_LINE_ENDS. In a container
whose ComponentOrientation is set to ComponentOrientation.LEFT_TO_RIGHT, these
constants map to NORTH, SOUTH, WEST, and EAST, respectively

Mixing the two types of constants can lead to unpredicable results. If you use both types, the
relative constants will take precedence. For example, if you add components using both the
NORTH and BEFORE_FIRST_LINE constants in a container whose orientation is
LEFT_TO_RIGHT, only the BEFORE_FIRST_LINE will be layed out.

FlowLayout

A flow layout arranges components in a left-to-right flow, much like lines of text in a paragraph.
Flow layouts are typically used to arrange buttons in a panel. It will arrange buttons left to right
until no more buttons fit on the same line. Each line is centered.

GridLayout

The GridLayout class is a layout manager that lays out a container's components in a rectangular
grid. The container is divided into equal-sized rectangles, and one component is placed in each
rectangle.The number of rows and columns can be specified as integers to the constructor or
set with the methods setRows and setColumns.

example setLayout(new GridLayout(3,2));

//  called within the constructor of a component class extension will set the layout to a grid of three rows
//  and  two columns.

If the number of rows and the number of columns have been set to non-zero values, the number
of columns specified is ignored. Instead, the number of columns is determined from the
specified number or rows and the total number of components in the layout. So, for
example, if three rows and two columns have been specified and nine components are added
to the layout, then they will be displayed as three rows of three columns. Specifying the number
of columns affects the layout only when the number of rows is set to zero. // something to test

CardLayout

The behaviour of card layout has been supplanted by the easy to use JTabbedPane swing
component. Still the layout is available for your use and is your only choice for the type of
behaviour it exhibits in AWT. CardLayout treats each component in the container as a card.
Only one card is visible at a time, and the container acts as a stack of cards. The first
component added to a CardLayout object is the visible component when the container is
first displayed. The ordering of cards is determined by the container's own internal ordering
of its component objects. CardLayout defines a set of methods that allow an application to
flip through these cards sequentially, or to show a specified card. The CardLayout's
addLayoutComponent( ) method can be used to associate a string identifier with a given
card for fast random access.
 



New Swing Layouts

BoxLayout

Swing introduces the Box container and it's associated BoxLayout  BoxLayout allows multiple
components to be layered out either vertically or horizontally. The components will not wrap so,
for example, a vertical arrangement of components will stay vertically arranged when the frame
is resized. Nesting multiple panels with different combinations of horizontal and vertical can create
an effect similar to GridBagLayout.You can nest multiple boxes and add components to them to
get the arrangement you want. When you create a BoxLayout, you specify whether its major axis
is the X axis (which means left to right placement) or Y axis (top to bottom placement).
Components are arranged from left to right (or top to bottom), in the same order as they were
added to the container.

Instead of using BoxLayout directly, many programs use the Box class. The Box class provides
a lightweight container that uses a BoxLayout. Box also provides handy methods to help you use
BoxLayout well.

BoxLayout attempts to arrange components at their preferred widths (for left to right layout) or
heights (for top to bottom layout). For a left to right layout, if not all the components are the
same height, BoxLayout attempts to make all the components as high as the highest component.
If that's not possible for a particular component, then BoxLayout aligns that component vertically,
according to the component's Y alignment. By default, a component has an Y alignment of 0.5,
which means that the vertical center of the component should have the same Y coordinate as the
vertical centers of other components with 0.5 Y alignment.     // from the jdk API

Similarly, for a vertical layout, BoxLayout attempts to make all components in the column as wide
as the widest component; if that fails, it aligns them horizontally according to their X alignments.
 


GridBagLayout                                               // for reference  from the JDK1.2.2 API documentation
 

 The GridBagLayout class is a flexible layout manager that aligns components vertically and 
 horizontally, without requiring that the components be of the same size. Each GridBagLayout 
 object maintains a dynamic rectangular grid of cells, with each component occupying one or 
 more cells, called its display area. Each component managed by a grid bag layout is associated 
 with an instance of GridBagConstraints that specifies how the component is laid out within 
 its display area.  // each component is associated with a grid-bag constraint object

 How a GridBagLayout object places a component set depends on the GridBagConstraints 
 object associated with each component, and on the minimum size and the preferred size of 
 the components' containers. 

 To use a grid bag layout effectively, you must customize one or more GridBagConstraints
 objects that are associated with its components. You customize a GridBagConstraints object 
 by setting one or more of its instance variables: 

 GridBagConstraints.gridx, GridBagConstraints.gridy     // gridx & gridy
  Specifies the cell at the upper left of the component's display area, where the upper-left-most
  cell has address gridx = 0, gridy = 0. Use GridBagConstraints.RELATIVE (the default value) 
   to specify that the component be just placed just to the right of (for gridx) or just below (for 
   gridy) the component that was added to the container just before this component was added. 

 GridBagConstraints.gridwidth, GridBagConstraints.gridheight  //gridwidth & gridheight
  Specifies the number of cells in a row (for gridwidth) or column (for gridheight) in the
 component's display area. The default value is 1. Use GridBagConstraints.REMAINDER
 to specify that the component be the last one in its row (for gridwidth) or column (for
 gridheight). Use GridBagConstraints.RELATIVE to specify that the component be the
  next to last one in its row (for gridwidth) or column (for gridheight). 

 GridBagConstraints.fill        // fill
 Used when the component's display area is larger than the component's requested 
 size to determine whether (and how) to resize the component. Possible values are 
 GridBagConstraints.NONE ( the default ), GridBagConstraints.HORIZONTAL (make
 the component wide enough to fill its display area horizontally, but don't change its 
 height),  GridBagConstraints.VERTICAL (make the component tall enough to fill its 
 display area vertically, but don't change its width), and GridBagConstraints.BOTH
 (make the component fill its display area entirely). 

 GridBagConstraints.ipadx, GridBagConstraints.ipady   // ipadx & ipady
  Specifies the component's internal padding within the layout, how much to add to the
  minimum size of the component. The width of the component will be at least its minimum
  width plus (ipadx * 2) pixels (since the padding applies to both sides of the component).
  Similarly, the height of the component will be at least the minimum height plus (ipady * 2)
  pixels. 

 GridBagConstraints.insets    // insets
  Specifies the component's external padding, the minimum amount of space between 
  the component and the edges of its display area. 

  GridBagConstraints.anchor    // anchor locates component when smaller than display
  Used when the component is smaller than its display area to determine where (within 
  the display area) to place the component. Valid values are GridBagConstraints.CENTER
  (the default), GridBagConstraints.NORTH, GridBagConstraints.NORTHEAST,
  GridBagConstraints.EAST, GridBagConstraints.SOUTHEAST,
  GridBagConstraints.SOUTH, GridBagConstraints.SOUTHWEST,
  GridBagConstraints.WEST, and GridBagConstraints.NORTHWEST. 

 GridBagConstraints.weightx, GridBagConstraints.weighty    // weightx & weighty
  Used to determine how to distribute space, which is important for specifying resizing
  behavior. Unless you specify a weight for at least one component in a row (weightx) 
  and column (weighty), all the components clump together in the center of their container. 
  This is because when the weight is zero (the default ), the GridBagLayout object puts 
  any extra space between its grid of cells and the edges of the container. 



The following figure shows ten components (all buttons) managed by a grid bag layout: 
Each of the ten components has the fill field of its associated GridBagConstraints object set
to GridBagConstraints.BOTH. In addition, the components have the following non-default
constraints: 


     Button1, Button2, Button3: weightx = 1.0 
     Button4: weightx = 1.0, gridwidth = GridBagConstraints.REMAINDER 
     Button5: gridwidth = GridBagConstraints.REMAINDER 
     Button6: gridwidth = GridBagConstraints.RELATIVE 
     Button7: gridwidth = GridBagConstraints.REMAINDER 
     Button8: gridheight = 2, weighty = 1.0 
     Button9, Button 10: gridwidth = GridBagConstraints.REMAINDER 

Here is the code that implements the example shown above: 

      import java.awt.*;
      import java.util.*;
      import java.applet.Applet;

      public class GridBagEx1 extends Applet {

          protected void makebutton(String name,
                                    GridBagLayout gridbag,
                                    GridBagConstraints c) {
              Button button = new Button(name);
              gridbag.setConstraints(button, c);
              add(button);
          }

          public void init() {
              GridBagLayout gridbag = new GridBagLayout();
              GridBagConstraints c = new GridBagConstraints();

              setFont(new Font("Helvetica", Font.PLAIN, 14));
              setLayout(gridbag);

              c.fill = GridBagConstraints.BOTH;
              c.weightx = 1.0;
              makebutton("Button1", gridbag, c);
              makebutton("Button2", gridbag, c);
              makebutton("Button3", gridbag, c);

                c.gridwidth = GridBagConstraints.REMAINDER; //end row
              makebutton("Button4", gridbag, c);

              c.weightx = 0.0;                  //reset to the default
              makebutton("Button5", gridbag, c); //another row

                c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last in row
              makebutton("Button6", gridbag, c);

                c.gridwidth = GridBagConstraints.REMAINDER; //end row
              makebutton("Button7", gridbag, c);

                c.gridwidth = 1;                //reset to the default
                c.gridheight = 2;
              c.weighty = 1.0;
              makebutton("Button8", gridbag, c);

              c.weighty = 0.0;                  //reset to the default
                c.gridwidth = GridBagConstraints.REMAINDER; //end row
                c.gridheight = 1;               //reset to the default
              makebutton("Button9", gridbag, c);
              makebutton("Button10", gridbag, c);

              setSize(300, 100);
          }

          public static void main(String args[]) {
                Frame f = new Frame("GridBag Layout Example");
                GridBagEx1 ex1 = new GridBagEx1();

                ex1.init();

                f.add("Center", ex1);
                f.pack();
                f.setSize(f.getPreferredSize());
                f.show();
          }
      }