CS 4773 Object Oriented Systems
GridBagLayout


Previous Topic: Assignment 4

Introduction
GridBagConstraints
Weights
Anchors
Fill
Position (End of class, Thursday, April 9)
Internal Padding
Width and Height
Insets
Some Additional Examples

Next Topic: Not Ready Yet


Much of this material is based on examples from:
"The Java Class Libraries Second Edition, Volume 2 by Chan and Lee.

There are also useful tutorials available on the web:



Introduction

The GridBagLayout can be used to lay out components in a grid.
Unlike the GridLayout the the sizes of the grids do not need to be constant, and a component can occupy more (or less) than one row or column.

Some of the information that the GridBagLayout needs to know about an object are:

This information is stored in an object of type GridBagContstraints and is associated with a component using
setContraints(Component, GridBagContraints)
This causes the layout manager to make a copy of the constraints and associate them with the object.
Therefore you only need one of these GridBagContraints objects.

Here is a very simple example. The two buttons move the smaller button to either the northeast or southwest positions within its area.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class GB01 extends Applet implements ActionListener {

   Button B1 = new Button("NE");
   Button B2 = new Button("SouthWest");
   GridBagLayout gridbag;

   public void init() {
      setup_layout();
   }

   private void setup_layout() {
      setBackground(Color.yellow);
      gridbag = new GridBagLayout();
      GridBagConstraints c = new GridBagConstraints();
      setLayout(gridbag);
      c.weightx = 1;
      c.weighty = 1;
      c.gridx = 0;
      c.gridy = 0;
      c.anchor = GridBagConstraints.SOUTHWEST;
      gridbag.setConstraints(B1,c);
      B1.setBackground(Color.cyan);
      add(B1);
      c.weightx = 0;
      c.gridx = 1;
      c.anchor = GridBagConstraints.NORTH;
      c.fill = GridBagConstraints.BOTH;
      gridbag.setConstraints(B2,c);
      B2.setBackground(Color.pink);
      add(B2);
      B1.addActionListener(this);
      B2.addActionListener(this);
   }

   public void actionPerformed(ActionEvent e) {
      GridBagConstraints c = gridbag.getConstraints(B1);
      if (e.getSource() == B1) {
         c.anchor = GridBagConstraints.NORTHEAST;
         showStatus("NE pushed");
      }
      else if (e.getSource() == B2) {
         c.anchor = GridBagConstraints.SOUTHWEST;
         showStatus("SouthWest pushed");
      }
      gridbag.setConstraints(B1,c);
      invalidate();
      validate();
   }
}
Here is what the applet looks like:

Push here to run this example.

Each component is associated with on area which may be one or more grid rectangles.

The number of rows and columns in the grid is determined by the largest values of gridx and gridy.

The anchor attribute indicates where in the grid the component will appear in its area if it does not exactly fill its area.

The fill attribute determines whether the components should be stretched to fill the entire area.

The weight attributes determine the various sizes of the grid areas.

In the above example, there is only one row which has two grid columns. Since the B2 button has weightx = 0, its column is as small as possible and the column for B1 fills up the rest of the space.

The B2 button is set to fill its entire area, which the B1 button is not (the default).

Pushing the buttons changes where the B1 button is anchored.


GridBagConstraints

The following is a complete list of all of the constraints:

Weights

The weights determine how the extra space is distributed after the components are laid out using their preferred sizes.

The algorithm for doing this is simple in the case in which all components have gridwidth and gridheight equal to 1.
In this case the weight of a grid column or row is the maximal weight of any component in that column or row.
The extra space is divided based on these weights.
For example, if the total weight of all of the columns is 10, then a column with weight 4 would get 4/10 of the total extra space.

If there are components which span more than one row or column, the weights are first determined by those components spanning only one row and column.
Then each additional component is handled in the order it was added. If its weight is less than the total weights of the rows or columns it spans, it has not effect.
Otherwise, its extra weight is distributed based on the weights of those rows or columns it spans.

If the extra space is negative, the layout manager squeezes things and you have not control over how this is done.

Here is a simple example which shows how weights can be used. It is a modified form of the applet described in Chan and Lee on page 757.

Note the use of invalidate and validate.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class GB02 extends Applet implements ActionListener {

   GridBagLayout gbl = new GridBagLayout();
   Color[] colors = {Color.yellow, Color.pink, Color.green, Color.red,
               Color.magenta, Color.cyan};


   public void init() {
      setup_layout();
   }

   private void setup_layout() {
      setLayout(gbl);
      for (int i=0; i<5; i++) {
          makeButton(i,colors[i]);
      }
   }

   void makeButton(int w, Color C) {
       GridBagConstraints c = new GridBagConstraints();
       Button b = new Button("" + w);
       b.setBackground(C);

       c.weightx = w;
       c.weighty = 1;
       c.fill = GridBagConstraints.BOTH;
       gbl.setConstraints(b, c);
       b.addActionListener(this);
       add(b);
   }

   public void actionPerformed(ActionEvent evt) {
       Button b = (Button)evt.getSource();
       GridBagConstraints gbc = gbl.getConstraints(b);

       if (++gbc.weightx > 4) {
           gbc.weightx = 0;
       }
       gbl.setConstraints(b, gbc);
       b.setLabel("" + gbc.weightx);
       invalidate();
       validate();
   }

}
This produces the following:

Push here to run this example.

Notice that the width of the button is not proportional to its weight since the weight only determines the allocation of the extra space after each component is laid out using its preferred size.

For a button, the preferred width is determined by the width of its label.

We can fix this by changing the preferred width to 0.
Unfortunately, there is not a setPreferredSize method in Java, only a getPreferredSize which the layout manager uses to determine the preferred size of a component.
We can solve this problem by making our own class that extends Button and overrides getPreferredSize.

Here is a modification of the previous example that shows what happens when you set the preferred size of a component to 0.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

// Like a Button, but allows the setting of a preferred width
class MyButton extends Button {
   int preferred_width;
   public MyButton(String lab, int preferred_width) {
      super(lab);
      this.preferred_width = preferred_width;
   }

   public Dimension getPreferredSize() {
      Dimension preferred_dimension;
      preferred_dimension = new Dimension(super.getPreferredSize());
      if (preferred_width >= 0)
         preferred_dimension.width = preferred_width;
      return preferred_dimension;
   }
}

public class GB02a extends Applet implements ActionListener {

   GridBagLayout gbl_top = new GridBagLayout();
   GridBagLayout gbl_bot = new GridBagLayout();
   Panel top;
   Panel bot;
   Button[] top_buttons;
   Button[] bot_buttons;
   Button reset_button;
   Color[] colors = {Color.yellow, Color.pink, Color.green, 
                     Color.magenta, Color.cyan};

   public void init() {
      setup_layout();
   }

   private void setup_layout() {
      top = new Panel();
      bot = new Panel();
      setLayout(new GridLayout(3,1));
      top.setLayout(gbl_top);
      bot.setLayout(gbl_bot);
      add(top);
      add(bot);
      add(reset_button = new Button("Reset Bottom"));
      reset_button.addActionListener(this);
      reset_button.setBackground(Color.red);
      top_buttons = new Button[5];
      bot_buttons = new Button[5];
      for (int i=0; i<5; i++) {
          top_buttons[i] = makeButton(top,gbl_top,-1,i,0,i,colors[i]);
      }
      for (int i=0; i<5; i++) {
          bot_buttons[i] = makeButton(bot,gbl_bot,0,i,1,i,colors[i]);
      }
   }

   private void relayout() {
      top.invalidate();
      bot.invalidate();
      validate();
   }
      
   Button makeButton(Panel p, GridBagLayout gbl, 
                   int width, int x, int y, int w, Color C) {
       GridBagConstraints c = new GridBagConstraints();
       MyButton b = new MyButton("" + w,width);
       b.setBackground(C);

       c.weightx = w;
       c.weighty = 1;
       c.gridx = x;
       c.gridy = y;
       c.fill = GridBagConstraints.BOTH;
       gbl.setConstraints(b, c);
       b.addActionListener(this);
       p.add(b);
       return b;
   }

   public void actionPerformed(ActionEvent evt) {
       GridBagLayout gbl;
       GridBagConstraints gbc;
       gbl = null;
       Button b = (Button)evt.getSource();
       if (b == reset_button) {
          for (int i=0;i<5;i++) {
             b = bot_buttons[i];
             gbc = gbl_bot.getConstraints(b);
             gbc.weightx = 1;
             b.setLabel("1");
             gbl_bot.setConstraints(b, gbc);
          }
          relayout();
          return;
       }
       for (int i=0;i<5;i++) {
          if (b == top_buttons[i]) {
             gbl = gbl_top;
             break; 
          }
          if (b == bot_buttons[i]) {
             gbl = gbl_bot;
             break; 
          }
       }
       if (gbl == null) return;
       gbc = gbl.getConstraints(b);
       if (++gbc.weightx > 4) {
           gbc.weightx = 0;
       }
       gbl.setConstraints(b, gbc);
       b.setLabel("" + gbc.weightx);
       relayout();
   }

}
The top row is made up of ordinary buttons.
The second row has buttons with preferred width 0.
Notice that the first button of this row has preferred width 0 and weight 0 so it does not show up.
Pushing the Reset Bottom button sets the weights of all of the buttons on the second row to 1.

The applet looks like this:

Push here to run this example.


Anchors

There are nine anchor types specifying 8 basic compass positions and the center position.

Here is a simple applet which is taken from Chan and Lee, page 741 and illustrates the possibilities.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class GB03 extends Applet implements ActionListener {

   Component centerButton;
   GridBagLayout gbl = new GridBagLayout();

   public void init() {
      setup_layout();
   }

   private void setup_layout() {
      setBackground(Color.yellow);
      GridBagConstraints c = new GridBagConstraints();

      setLayout(gbl);
      c.fill = GridBagConstraints.BOTH;
      c.weightx = 1;
      c.weighty = 1;

      makeButton(this, "nw", c, 0, 0, Color.cyan);
      makeButton(this, "n", c, 1, 0, Color.cyan);
      makeButton(this, "ne", c, 2, 0, Color.cyan);
      makeButton(this, "w", c, 0, 1, Color.cyan);
      makeButton(this, "e", c, 2, 1, Color.cyan);
      makeButton(this, "sw", c, 0, 2, Color.cyan);
      makeButton(this, "s", c, 1, 2, Color.cyan);
      makeButton(this, "se", c, 2, 2, Color.cyan);

      //   Make center button.
      c.fill = GridBagConstraints.NONE;
      centerButton = makeButton(this, "C", c, 1, 1,Color.pink);
   }

   Component makeButton(Container cont, String label, 
           GridBagConstraints c, int x, int y, Color C) {
       GridBagLayout gbl = (GridBagLayout)cont.getLayout();
       Button b = new Button(label);

       cont.add(b);
       c.gridx = x;
       c.gridy = y;
       gbl.setConstraints(b, c);
       b.setBackground(C);
       b.addActionListener(this);
       return b;
   }

   public void actionPerformed(ActionEvent evt) {
       String arg = evt.getActionCommand();
       GridBagConstraints c = gbl.getConstraints(centerButton);
       
       if ("n".equals(arg)) 
           c.anchor = GridBagConstraints.NORTH;
       else if ("s".equals(arg))
           c.anchor = GridBagConstraints.SOUTH;
       else if ("e".equals(arg))
           c.anchor = GridBagConstraints.EAST;
       else if ("w".equals(arg))
           c.anchor = GridBagConstraints.WEST;
       else if ("nw".equals(arg))
           c.anchor = GridBagConstraints.NORTHWEST;
       else if ("ne".equals(arg))
           c.anchor = GridBagConstraints.NORTHEAST;
       else if ("sw".equals(arg)) 
           c.anchor = GridBagConstraints.SOUTHWEST;
       else if ("se".equals(arg)) 
           c.anchor = GridBagConstraints.SOUTHEAST;
       else if ("C".equals(arg)) 
           c.anchor = GridBagConstraints.CENTER;
       gbl.setConstraints(centerButton, c);
       invalidate();
       validate();
   }

}
It produces the following display:

Push here to run this example.


Fill

The four fill types are NONE (the default), VERTICAL, HORIZONTAL, and BOTH. They affect components whose preferred size does not completely fill their grid area.

Here is a simple applet which which is taken from Chan and Lee, page 744 and illustrates the possibilities.
It shows four labels with the four fill types.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class GB04 extends Applet {
   GridBagLayout gbl = new GridBagLayout();
   GridBagConstraints c = new GridBagConstraints();

   public void init() {
      setup_layout();
   }

   private void setup_layout() {
      setBackground(Color.yellow);
      setLayout(gbl);
      c.weightx = 1;
      c.weighty = 1;
      makeLabel(0,0,"none", GridBagConstraints.NONE);
      makeLabel(1,0,"horizontal", GridBagConstraints.HORIZONTAL);
      makeLabel(0,1,"vertical", GridBagConstraints.VERTICAL);
      makeLabel(1,1,"both", GridBagConstraints.BOTH);
    }

    private void makeLabel(int x, int y, String label, int fill) {
        Label b = new Label(label, Label.CENTER);
        b.setBackground(Color.cyan);
        b.setForeground(Color.black);
        add(b);
        c.fill = fill;
        c.gridx = x;
        c.gridy = y;
        gbl.setConstraints(b, c);
    }

}
It produces the following display:

Push here to run this example, but it doesn't do much.


Position

The gridx and gridy fields determine the positioning of the components. The default is to put the object in the position after the last one which was added.

The following example is taken from Chan and Lee, page 748 and shows a use of these fields. Clicking on a button moves it to the free space if it is adjacent to the free space. Otherwise it produces a beep.
The constraints are used to determine the current position of the button pushed.
Notice how the toolkit is used to produce the beep.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class GB05 extends Applet implements ActionListener {

   GridBagLayout gbl = new GridBagLayout();
   Point free = new Point(2, 2);

   public void init() {
      setup_layout();
   }

   private void setup_layout() {
      Component c = null;

      setLayout(gbl);
      for (int i=0; i<3; i++) {
          for (int j=0; j<3; j++) {
              c = makeButton(String.valueOf((char)('1'+i+3*j)), i, j);
              c.setBackground(Color.cyan);
          }
      }
      remove(c);       // remove the last button
   }

   // Returns the new button.
   Component makeButton(String label, int x, int y) {
      GridBagConstraints c = new GridBagConstraints();
      Button b = new Button(label);

      c.gridx = x;
      c.gridy = y;
      c.fill = GridBagConstraints.BOTH;
      c.weightx = 1;
      c.weighty = 1;
      gbl.setConstraints(b, c);
      add(b);
      b.addActionListener(this);
      return b;
   }

   public void actionPerformed(ActionEvent evt) {
      Button button = (Button)evt.getSource();
       GridBagConstraints gbc = gbl.getConstraints(button);
       Point p = new Point(gbc.gridx, gbc.gridy);

       if ((p.x == free.x && Math.abs(p.y-free.y) == 1) 
              || (p.y == free.y && Math.abs(p.x-free.x) == 1)) {
          gbc.gridx = free.x;
          gbc.gridy = free.y;
          gbl.setConstraints(button, gbc);
          free = p;
          invalidate();
          validate();
      }
      else {
         Toolkit.getDefaultToolkit().beep();
      }
   }

}

The applet looks like this:

Push here to run this example.


Internal Padding

The fields ipadx and ipady can be used to modify the minimum or preferred size of a component. For a button, the preferred width is determined by the length of its label and the preferred height is determined by the font used for the label. See the example below.

Width and Height

The gridwidth and gridheight fields determine the number of cells that are included in a component's area.

The possible values are a (small) positive integer, or one of the special values REMAINDER or RELATIVE.

REMAINDER means the component will occupy all of the cells to the right or below it.

RELATIVE means the component will occupy all of the cells to the right or below it except for the last cell.

Here is a simple applet which illustrates the possibilities.
It is loosely based on the example from Chan and Lee, page 746.
When you click on a button, its width is incremented unless it was 4, in which case the width is reset to 1.
Color has been added and the height of the buttons is varied using internal padding so that it is easier to see what is happening.

You have no guarantee as to which buttons will be on top of which.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class GB06 extends Applet implements ActionListener {

    GridBagLayout gbl = new GridBagLayout();
    Button[][] buttons;
    Color[] colors = {Color.yellow, Color.pink, Color.green, Color.red, 
               Color.magenta, Color.cyan};

   public void init() {
      setup_layout();
   }

   public void setup_layout() {
      setLayout(gbl);
      buttons = new Button[3][6];
      for (int i=0; i<3; i++) 
         for (int j=0;j<6;j++) {
             if (j == 5) 
                buttons[i][j] =
                   makeButton(i,j,j*10,"Long Name", false);
             else 
                buttons[i][j] = makeButton(i,j,j*10,"1", true);
             buttons[i][j].setBackground(colors[j]);
          }
   }

    Button makeButton(int y, int x, int pady, String label, 
                      boolean action_flag) {
        GridBagConstraints c = new GridBagConstraints();
        Button b = new Button(label);

        c.gridwidth = 1;
        c.gridheight = 1;
        c.gridx = x;
        c.gridy = y;
        c.ipady = pady;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.weightx = 1;
        c.weighty = 1;
        c.anchor = GridBagConstraints.SOUTH;
        gbl.setConstraints(b, c);
        add(b);
        if (action_flag)
           b.addActionListener(this);
        return b;
    }

    public void actionPerformed(ActionEvent evt) {
        Button b = (Button)evt.getSource();
        GridBagConstraints gbc = gbl.getConstraints(b);
        if (++gbc.gridwidth > 4) 
            gbc.gridwidth = 1;
        gbl.setConstraints(b, gbc);
        b.setLabel("" + gbc.gridwidth);
        invalidate();
        validate();
    }

}
It produces the following display:

Push here to run this example.


The above example shows the explicit setting of the positions and widths of the cells.
By default, a cell is placed right after the previous one.

By setting a width or height to REMAINDER, the component will occupy all cells to the right or below it.

By setting the width or height to Relative, the component will occupy all cells to the right or below, except for the last one.

This is illustrated by the following applet:

import java.awt.*;
import java.applet.*;

public class GB06a extends Applet {

   GridBagLayout gbl = new GridBagLayout();

   public void init() {
      setup_layout();
   }

   public void setup_layout() {
      setLayout(gbl);
      for (int i=0; i<9; i++) makeButton("1", 1, Color.cyan);
      makeButton("REMAINDER", GridBagConstraints.REMAINDER, Color.cyan);
      
      makeButton("1", 1, Color.yellow);
      makeButton("REMAINDER", GridBagConstraints.REMAINDER, Color.yellow);

      makeButton("1", 1, Color.pink);
      makeButton("1", 1, Color.pink);
      makeButton("1", 1, Color.pink);
      makeButton("RELATIVE", GridBagConstraints.RELATIVE, Color.pink);
      makeButton("REMAINDER", GridBagConstraints.REMAINDER, Color.pink);
   }

   void makeButton(String label, int w, Color C) {
      GridBagConstraints c = new GridBagConstraints();
      Button b = new Button(label);
      b.setBackground(C);

      c.gridwidth = w;
      c.gridheight = 1;
      c.fill = GridBagConstraints.BOTH;
      c.weightx = 1;
      c.weighty = 1;
      gbl.setConstraints(b, c);
      add(b);
   }
}
Here is another applet which shows the use of REMAINDER and RELATIVE:

Push here to run this example.


Insets

The insets field has four subfields, top, bottom, left, and right.
Each controls the size of the border around the component.
The defaults are all zero.
A negative inset allows a component to extend outside its area.

The following example is taken from Chan and Lee, page 750.

 
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class GB07 extends Applet implements ActionListener {

   Button centerButton;
   GridBagLayout gbl = new GridBagLayout();
   GridBagConstraints c = new GridBagConstraints();

   public void init() {
      setup_layout();
   }

   private void setup_layout() {
      setBackground(Color.yellow);

      setLayout(gbl);
      c.fill = GridBagConstraints.BOTH;
      c.weightx = 1;
      c.weighty = 1;

      makeButton("-top", 1, 0, Color.cyan);
      makeButton("+top", 2, 0, Color.cyan);
      makeButton("+left", 0, 1, Color.cyan);
      makeButton("-left", 0, 2, Color.cyan);
      makeButton("-bottom", 1, 3, Color.cyan);
      makeButton("+bottom", 2, 3, Color.cyan);
      makeButton("+right", 3, 1, Color.cyan);
      makeButton("-right", 3, 2, Color.cyan);

      // Make center button.
      c.gridwidth = 2;
      c.gridheight = 2;
      centerButton = makeButton("T0 L0 B0 R0", 1, 1, Color.pink);
   }

   // Returns the new button.
   Button makeButton(String label, int x, int y, Color C) {
      Button b = new Button(label);

      add(b);
      c.gridx = x;
      c.gridy = y;
      gbl.setConstraints(b, c);
      b.setBackground(C);
      b.addActionListener(this);
      return b;
   }

   public void actionPerformed(ActionEvent evt) {
      String s = evt.getActionCommand();
      int sign = s.charAt(0) == '+' ? 1 : -1;
    
      s = s.substring(1);
      if ("top".equals(s)) 
          c.insets.top += sign;
      else if ("left".equals(s))
          c.insets.left += sign;
      else if ("bottom".equals(s))
          c.insets.bottom += sign;
      else if ("right".equals(s))
          c.insets.right += sign;
      gbl.setConstraints(centerButton, c);
      centerButton.setLabel("T"+c.insets.top+" L"+c.insets.left
                            +" B"+c.insets.bottom+" R"+c.insets.right);
      invalidate();
      validate();
    }

}

The applet looks like this:

Push here to run this example.

Notice that sometimes when the insets are changed the sizes of the other buttons change. WHen does this occur and why?


Some Additional Examples

The following example shows the use of the fill type and anchor type.
It is loosely taken from an example by Newmarch.
Note the use of the class that extends panel to make it have a predetermined height.

 
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

// Like a Panel, but allows the setting of a preferred width and height
class MyPanel extends Panel {
   int preferred_width;
   int preferred_height;

   public MyPanel(int preferred_width, int preferred_height) {
      super();
      this.preferred_width = preferred_width;
      this.preferred_height = preferred_height;
   }

   public Dimension getPreferredSize() {
      Dimension preferred_dimension;
      preferred_dimension = new Dimension(super.getPreferredSize());
      if (preferred_width >= 0)
         preferred_dimension.width = preferred_width;
      if (preferred_height >= 0)
         preferred_dimension.height = preferred_height;
      return preferred_dimension;
   }
}

public class GB08 extends Applet implements ItemListener {

   Button B;
   GridBagLayout gridbag;
   GridBagConstraints c;
   Panel N;
   Checkbox[] fillboxes;
   Checkbox[] anchorboxes;
   int[] fillstate = {GridBagConstraints.NONE,GridBagConstraints.HORIZONTAL,
                      GridBagConstraints.VERTICAL,GridBagConstraints.BOTH};
   int[] anchorstate = {GridBagConstraints.CENTER, GridBagConstraints.NORTH,
                        GridBagConstraints.NORTHEAST, GridBagConstraints.EAST,
                        GridBagConstraints.SOUTHEAST, GridBagConstraints.SOUTH,
                        GridBagConstraints.SOUTHWEST, GridBagConstraints.WEST,
                        GridBagConstraints.NORTHWEST};
   public void init() {
      setup_layout();
   }

   private void setup_layout() {
      B = new Button("button");
      CheckboxGroup fillcheck = new CheckboxGroup();
      CheckboxGroup anchorcheck = new CheckboxGroup();
      fillboxes = new Checkbox[4];
      anchorboxes = new Checkbox[9];
      gridbag = new GridBagLayout();
      c = new GridBagConstraints();
      setBackground(Color.yellow);
      setLayout(new BorderLayout());
      N = new MyPanel(-1,100);
      Panel W = new Panel();
      Panel E = new Panel();
      N.setBackground(Color.pink);
      E.setBackground(Color.cyan);
      W.setBackground(Color.cyan);
      add("North",N);
      add("East",E);
      add("West",W);
      N.setLayout(gridbag);
      B.setBackground(Color.magenta);
      c.gridx = 0;
      c.gridy = 0;
      c.weightx = 1.0;
      c.weighty = 1.0;
      gridbag.setConstraints(B,c);
      N.add(B);
      E.setLayout(new BorderLayout());
      W.setLayout(new BorderLayout());
      Panel WT = new Panel();
      Panel ET = new Panel();
      W.add("North",WT);
      E.add("North",ET);
      WT.setLayout(new GridLayout(5,1));
      WT.add(new Label("Fill Type",Label.CENTER));
      fillboxes[0] = makeCheckbox("None",fillcheck,true,WT);
      fillboxes[1] = makeCheckbox("Horizontal",fillcheck,false,WT);
      fillboxes[2] = makeCheckbox("Vertical",fillcheck,false,WT);
      fillboxes[3] = makeCheckbox("Both",fillcheck,false,WT);
      ET.setLayout(new GridLayout(10,1));
      ET.add(new Label("Anchor Type",Label.CENTER));
      anchorboxes[0] = makeCheckbox("Center",anchorcheck,true,ET);
      anchorboxes[1] = makeCheckbox("North",anchorcheck,false,ET);
      anchorboxes[2] = makeCheckbox("NorthEast",anchorcheck,false,ET);
      anchorboxes[3] = makeCheckbox("East",anchorcheck,false,ET);
      anchorboxes[4] = makeCheckbox("SouthEast",anchorcheck,false,ET);
      anchorboxes[5] = makeCheckbox("South",anchorcheck,false,ET);
      anchorboxes[6] = makeCheckbox("SouthWest",anchorcheck,false,ET);
      anchorboxes[7] = makeCheckbox("West",anchorcheck,false,ET);
      anchorboxes[8] = makeCheckbox("NorthWest",anchorcheck,false,ET);
   }

   public Checkbox makeCheckbox(String label, CheckboxGroup cbg, 
                                boolean value, Panel p) {
      Checkbox cb;
      cb = new Checkbox(label,cbg,value);
      p.add(cb);
      cb.addItemListener(this);
      return cb;
   }

   public void itemStateChanged(ItemEvent e) {
      for (int i=0;i<4;i++)
         if (fillboxes[i].getState()) {
            c.fill = fillstate[i];
         }
      for (int i=0;i<9;i++)
         if (anchorboxes[i].getState()) {
            c.anchor = anchorstate[i];
         }
      gridbag.setConstraints(B,c);
      N.invalidate();
      validate();
   }
}

The applet looks like this:

Push here to run this example.


The following example shows how to put labels on a TextField.
It would work equally will with a ScrollBar. It is taken from an example in Chan and Lee on Page 761.

 
import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class GB09 extends Applet {

   public void init() {
      setup_layout();
   }

   private void setup_layout() {
      Label L;
      TextField T1,T2,T3;
      GridBagLayout gridbag;
      GridBagConstraints c;
      setBackground(Color.cyan);
      gridbag = new GridBagLayout();
      c = new GridBagConstraints();
      setLayout(gridbag);
      c.fill = GridBagConstraints.BOTH;
      c.gridx = 0;
      c.gridy = 0;
      c.weightx = 0.0;
      c.weighty = 0.0;
      L = new Label("Name:");
      gridbag.setConstraints(L,c);
      add(L);
      c.weightx = 1.0;
      c.gridx = 1;
      T1 = new TextField();
      gridbag.setConstraints(T1,c);
      add(T1);
      c.weightx = 0.0;
      c.gridx = 0;
      c.gridy = 1;
      L = new Label("Address:"); 
      gridbag.setConstraints(L,c); 
      add(L);
      c.weightx = 1.0; 
      c.gridx = 1;   
      T2 = new TextField(); 
      gridbag.setConstraints(T2,c);
      add(T2);
      c.weightx = 0.0; 
      c.gridx = 0; 
      c.gridy = 2;
      L = new Label("Phone:"); 
      gridbag.setConstraints(L,c); 
      add(L);
      c.weightx = 1.0; 
      c.gridx = 1;   
      T3 = new TextField(); 
      gridbag.setConstraints(T3,c);
      add(T3);
   }
}

The applet looks like this:

Push here to run this example.

We can make this look a little better by adding the following two line of code.

      c.insets.left = 3;
      c.insets.right = 3;
The applet then looks like this:

Push here to run this example.


The following example is a modified version of the example on page 774 of Chan and Lee.
It illustrates the following points:

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class GB10 extends Applet {

   GridBagLayout gbl;
   Panel p;
   Label AppletLabel;
   Label CanvasLabel;
   int count = 0;

   public void init() {
      setup_layout();
      repaint(1);
   }

   private void setup_layout() {
      gbl = new GridBagLayout();
      p = new Panel();
      AppletLabel = new Label("");
      CanvasLabel = new Label("");
      setLayout(new BorderLayout());
      p.setLayout(gbl);
      setBackground(Color.yellow);
      for (int i=0; i<2; i++) {
          for (int j=0; j<2; j++) {
             makeCanvas("("+i+","+j+")", i, j);
          }
      }
      add(p, BorderLayout.CENTER); 
      add(AppletLabel, BorderLayout.SOUTH); 
      add(CanvasLabel, BorderLayout.NORTH); 
      p.addMouseMotionListener(new MouseMotionEventHandler());
   }

   class MouseMotionEventHandler extends MouseMotionAdapter {
      public void mouseMoved(MouseEvent evt) {
          int x = evt.getX();
          int y = evt.getY();
          count++;
          Point p = gbl.location(x, y);

          AppletLabel.setText(count+
             ": Applet x="+x+" y="+y+": ("+p.x+", "+p.y+")");
      }
   }

   void makeCanvas(String content, int x, int y) {
      GridBagConstraints c = new GridBagConstraints();
      MainCanvas cv = new MainCanvas(content,CanvasLabel);
      cv.setBackground(Color.cyan);

      p.add(cv);
      cv.setSize(40, 40);
      c.gridx = x;
      c.gridy = y;
      gbl.setConstraints(cv, c);
   }
}

class MainCanvas extends Canvas {
   String content;
   Label CanvasLabel;
   int count = 0;

   MainCanvas(String content, Label CanvasLabel) {
      this.content = content;
      this.CanvasLabel = CanvasLabel;
      addMouseMotionListener(new MouseMotionEventHandler());
   }

   public void paint(Graphics g) {
      int w = getSize().width;
      int h = getSize().height;
      FontMetrics fm = g.getFontMetrics();

      g.drawString(content, (w-fm.stringWidth(content))/2, 
          (h-fm.getHeight())/2+fm.getAscent());
      g.setColor(getBackground());
      g.draw3DRect(0, 0, w-1, h-1, false);
   }

   class MouseMotionEventHandler extends MouseMotionAdapter {
      public void mouseMoved(MouseEvent evt) {
          count++;
          CanvasLabel.setText(count+
             ": Canvas Point: "+evt.getX()+" "+evt.getY());
          evt.translatePoint(getLocation().x, getLocation().y);

          getParent().dispatchEvent(evt);
      }
   }
}
The applet then looks like this:

Push here to run this example.



Next topic: Not Ready Yet