An introduction to GridBagLayout

 

Overview

GridBagLayout arranges components in a flexible grid pattern that permits larger components to span multiple rows and columns. It is a powerful layout manager, but difficult to master. Fortunately, only a superficial knowledge of GridBagLayout is required for Java certification.

 

GridBagLayout

For example, a flexible grid of 4 rows and 4 columns can be made to appear as follows

 

 

 

 

 1

 

 

 

 

2

3

4

5

 

 6

 

where component 1 covers the first cell of rows one through three, component 2 covers the last three cells of row one, component 3 occupies the middle cells of rows two and three, components 4 and 5 cover the last cell of rows two and three respectively, and component 6 spans all four cells of row four.

setLayout(new GridBagLayout());

 

The GridBagConstraints class

 GridBagConstraints c = new GridBagConstraints();

creates a GridBagConstraints object having default settings. If someObject is an object to be added to the container, the general technique for adding it is to

  1. Modify one or more public instance variables of object c

  2. Add someObject to the container by coding

add(someObject, c);

  1. Repeat steps 1 and 2 for the next component.

gridx and gridy

Used to specify the cell address of the top-left corner of the component within the grid. The address of the top-left corner of the container is gridx = 0 and gridy = 0. Use GridBagConstraints.RELATIVE (the default value) to specify that the component be placed just to the right of (for gridx) or just below (for gridy) the previous component that was added to the container.

gridwidth and gridheight

Used to specify 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).

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

anchor

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.

weightx and 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. 

Other variables exist to control a component's internal padding and insets (the space that surrounds a component within its display area). Consult the Java API for more details.

 

A sample applet that uses GridBagLayout

The following applet demonstrates how GridBagLayout can be used manage components of various sizes:

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

public class App extends Applet {

  // Object references and variables to support "card" processing.

  Panel cards;
  CardLayout myCardLayout;
  int cardIndex;

  // Object references for user controls.

  Button next;
  Button previous;
  Choice pickOne;

  // Applet initialization.

  public void init() {
    resize(500, 350);
    setBackground(Color.lightGray);

    // Choose GridBagLayout and create a GridBagConstraints object
    // for use in laying out components to be added to the container.

    setLayout(new GridBagLayout());
    GridBagConstraints c = new GridBagConstraints();

    // Initialize constraints to stretch small components to fill
    // their entire display area, give all rows equal height when
    // distributing extra vertical space, and give all columns equal
    // width when distributing extra horizontal space.

    c.fill = GridBagConstraints.BOTH;
    c.weighty = 1;
    c.weightx = 1;

    // Build the "Card in View" label and add it to the top-left
    // cell in the layout.

    Label hdg = new Label("Card in view");
    hdg.setAlignment(Label.CENTER);
    hdg.setFont(new Font("SanSerif", Font.BOLD, 14));
    c.gridx = 0;
    c.gridy = 0;
    c.gridwidth = 1;
    c.gridheight = 1;
    add(hdg, c);

    // Build the choice menu and add it to the right-most 2 cells
    // of the first row of the layout.

    pickOne = new Choice();
    pickOne.addItem("Card 1");
    pickOne.addItem("Card 2");
    pickOne.addItem("Card 3");
    pickOne.addItemListener(
      new ItemListener() {
        public void itemStateChanged(ItemEvent e) {

          // Display the selected "card" within the container and
          // update the current card index being displayed.

          myCardLayout.show(cards, pickOne.getSelectedItem());
          cardIndex = pickOne.getSelectedIndex();
        }
      }
    );
    c.gridx = 1;
    c.gridy = 0;
    c.gridwidth = 2;
    c.gridheight = 1;
    add(pickOne, c);

    // Create the "Next" button and add it to the left-most cell
    // in the second row of the layout.

    next = new Button(">");
    next.setFont(new Font("SanSerif", Font.BOLD, 18));
    next.addActionListener(
      new ActionListener() {
        public void actionPerformed(ActionEvent e) {

          // Display the next "card" in the container and make
          // it the current selection in the Choice component

          myCardLayout.next(cards);
          if (cardIndex < cards.getComponentCount() - 1) {
            cardIndex++;
          }
          else {
            cardIndex = 0;
          }
          pickOne.select(cardIndex);
        }
      }
    );
    c.gridx = 0;
    c.gridy = 1;
    c.gridwidth = 1;
    c.gridheight = 1;
    add(next, c);

    // Instantiate objects and variables to support "card" processing.

    cards = new Panel();
    myCardLayout = new CardLayout();
    cardIndex = 0;

    // Build the container of "cards" and add it to the right-most two
    // cells of rows 2 and 3 in the layout. It is a large component.

    cards.setLayout(myCardLayout);
    Label x = new Label("Hello World!");
    x.setBackground(Color.black);
    x.setForeground(Color.white);
    x.setFont(new Font("Serif", Font.PLAIN, 36));
    x.setAlignment(Label.CENTER);
    cards.add(x, "Card 1");
    Label y = new Label("Java is Fun!");
    y.setBackground(Color.white);
    y.setForeground(Color.black);
    y.setFont(new Font("Serif", Font.PLAIN, 36));
    y.setAlignment(Label.CENTER);
    cards.add(y, "Card 2");
    Label z = new Label("Ferris State University");
    z.setBackground(Color.red);
    z.setForeground(Color.yellow);
    z.setFont(new Font("Serif", Font.PLAIN + Font.BOLD, 36));
    z.setAlignment(Label.CENTER);
    cards.add(z, "Card 3");
    c.gridx = 1;
    c.gridy = 1;
    c.gridwidth = 2;
    c.gridheight = 2;
    add(cards, c);

    // Create the "Previous" button and add it to the left-most cell
    // in the third row of the layout.

    previous = new Button("<");
    previous.setFont(new Font("SanSerif", Font.BOLD, 18));
    previous.addActionListener(
      new ActionListener() {
        public void actionPerformed(ActionEvent e) {

          // Display the previous "card" in the container and make
          // it the current selection in the Choice component

          myCardLayout.previous(cards);
          if (cardIndex > 0) {
            cardIndex--;
          }
          else {
            cardIndex = cards.getComponentCount() - 1;
          }
          pickOne.select(cardIndex);
        }
      }
    );
    c.gridx = 0;
    c.gridy = 2;
    c.gridwidth = 1;
    c.gridheight = 1;
    add(previous, c);
  }
}

Notes:

  1. Each component is placed in the container based upon its absolute cell position. This is done via the gridx and gridy variables of the GridBagConstraints object.

  2. The cell width and cell height of each component is specified via the gridwidth and gridheight variables of the GridBagConstraints object.

 

A sample windows program that uses GridBagLayout

The following windows program demonstrates how components can extend over multiple columns when using a GridBagLayout to manage the container:

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

public class App extends Frame implements ActionListener {

  // Object references.

  Button b1, b2, b3, b4, b5, b6, b7;
  Label msg;

  // Processing starts here.

  public static void main(String[] args) {
    App myWindow = new App("GridBagLayout");
    myWindow.setSize(300, 300);
    myWindow.setVisible(true);
  }

  // Class constructor.

  public App(String title) {
    super(title);
    addWindowListener(
      new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          dispose();
          System.exit(0);
        }
      }
    );

    setFont(new Font("SanSerif", Font.BOLD, 16));

    // Choose GridBagLayout and create a GridBagConstraints object
    // for use in laying out components to be added to the container.

    setLayout(new GridBagLayout());
    GridBagConstraints c = new GridBagConstraints();

    // Initialize constraints to stretch small components to fill
    // their entire display area, give all rows equal height when
    // distributing extra vertical space, and give all columns equal
    // width when distributing extra horizontal space.

    c.fill = GridBagConstraints.BOTH;
    c.weighty = 1;
    c.weightx = 1;

    // Build the first row of components.

    b1 = new Button("1");
    b1.addActionListener(this);
    add(b1, c);
    b2 = new Button("2");
    b2.addActionListener(this);
    add(b2, c);
    b3 = new Button("3");
    b3.addActionListener(this);
    c.gridwidth = GridBagConstraints.REMAINDER; // Last on row.
    add(b3, c);

    // Don't let subsequent rows determine how to allocate extra
    // horizontal space.

    c.weightx = 0;

    // Reset the grid width to one cell before building a new row.

    c.gridwidth = 1;

    // Build the second row of components.

    b4 = new Button("4");
    b4.addActionListener(this);
    add(b4, c);
    msg = new Label("Click one");
    msg.setAlignment(Label.CENTER);
    c.gridwidth = GridBagConstraints.REMAINDER; // Last on row.
    add(msg, c);

    // Reset the grid width to one cell before building a new row.

    c.gridwidth = 1;

    // Build the third row of components.

    b5 = new Button("5");
    b5.addActionListener(this);
    c.gridwidth = GridBagConstraints.RELATIVE; // Next to last on row.
    add(b5, c);
    b6 = new Button("6");
    b6.addActionListener(this);
    c.gridwidth = GridBagConstraints.REMAINDER; // Last on row.
    add(b6, c);

    // Reset the grid width to one cell before building a new row.

    c.gridwidth = 1;

    // Build the fourth row of components.

    b7 = new Button("7");
    b7.addActionListener(this);
    c.gridwidth = GridBagConstraints.REMAINDER; // Last on row.
    add(b7, c);
  }

  // Required method of the ActionListener interface.

  public void actionPerformed(ActionEvent e) {
    msg.setText("You clicked " + ((Button)e.getSource()).getLabel());
  }
}

Notes:

  1. Each component is placed in its row based upon its relative column position. The next to the last component is specified via the GridBagConstraints.RELATIVE constant and the last component specified via the GridBagConstraints.REMAINDER constant in conjunction with the gridx variable of the GridBagConstraints object.

  2. In this sample, all components have equal height.

 

Review questions

  1. If c is a GridBagConstraints object, which one of the following specifies that the top-left corner of the next component is to be placed in the second column of the first row of a container using GridBagLayout?

  1. c.gridx = 2;
    c.gridy = 1;

  1. c.gridx = 1;
    c.gridy = 0;

  2. c.gridx(2);
    c.gridy(1);

  3. c.gridx(1);
    c.gridy(0);

  4. c.setX(1);
    c.setY(0);

  1. If c is a GridBagConstraints object, which one of the following specifies that the next component is to be the last one in its column of a container using GridBagLayout?

  1. c.gridheight = GridBagConstraints.REMAINDER;

  1. c.gridwidth = GridBagConstraints.REMAINDER;

  2. c.gridheight(GridBagConstraints.RELATIVE);

  3. c.gridwidth(GridBagConstraints.RELATIVE);

  4. c.gridheight = GridBagConstraints.RELATIVE;

  1. Assume that someComponent is the object reference of a component and c is the object reference of a properly set GridBagConstraints object. If the current container is using GridBagLayout, which one of the following will place someComponent in the container?

    1. place(c, someComponent);

    1. place(someComponent, c);

    2. add(c, someComponent);

    3. add(someComponent, c);

    4. c.add(someComponent, this);

  1. Assume that c is the object reference of a GridBagConstraints object. Which one of the following specifies that a component too small to fill its display area will be positioned in the bottom-right corner of its display area?

  1. c.anchor(GridBagConstraints.SOUTHWEST);

  2. c.anchor = GridBagConstraints.SOUTHWEST;

  3. c.anchor(GridBagConstraints.SOUTHEAST);

  4. c.anchor = GridBagConstraints.SOUTHEAST;

  5. c.anchor(GridBagConstraints.SOUTH + GridBagConstraints.EAST);