[View INPRISE Home Page][View Product List][Search This Web Site][View Available Downloads][Join Inprise Membership][Enter Discussion Area][Send Email To Webmaster]
INPRISE Online And ZD Journals Present:



Taming the GridBagLayout class
By Tom Mitchell and Tim Gooch

New Java programmers must adjust to the concept of using layout managers. Developers coming from Visual Basic, Windows SDK, or other windowed backgrounds are often surprised to find that with Java, the user interface is built dynamically by code at runtime. JBuilder assists programmers by generating the user interface layout code for them. However, you’ll want to understand all the layout managers available in the Java Development Kit and how to use them effectively.

To place components in a grid pattern, the obvious layout manager is the GridLayout class. However, this class forces all the components in the grid to be the same size. If you want to use a grid pattern, but wish to place different sized components in this pattern, you’ll need to use the GridBagLayout class, along with associated GridBagConstraints objects for each component.

As you might expect, the GridBagLayout class has the most flexibility and functionality of the layout managers included in the JDK. Unfortunately, it’s also the most complex. To simplify using it, Borland added the GridBag Constraints Property Editor, which generates the appropriate GridBagConstraints objects for the GridBagLayout object. Many programmers avoid using this layout completely, choosing either to use a simpler layout manager or none at all. In this article, we’ll explain how GridBagLayout works and how to use it within JBuilder.

What’s the big deal?
So what’s the big deal about the GridBagLayout manager? Like all the other layout managers, it’s extended from the Object class and implements the LayoutManager2 interface. This is a change in JDK 1.1. Earlier layout managers implemented the LayoutManager interface. The LayoutManager2 interface extends LayoutManager, adding some new methods intended mainly for tools like JBuilder.

GridBagLayout differs from all the other layout managers in the complexity of the layout. While other layout managers allow simpler, predictable positioning and sizing of components into fairly uniform layouts, GridBagLayout has the flexibility to lay out components of varied sizes into an aligned layout, without requiring that all rows and heights be identical. (Obviously, though, the heights of the cells in a given row must all be the same, as must the widths of the cells in a given column.) However, you can also maintain tight control of the relative position of each component in the layout. That’s an intimidating description—but the individual concepts are fairly easy to understand.

Simple rules
There are a couple of simple rules that will help you understand and predict the GridBagLayout class’ behavior. They’re as follows:

  • As its name implies, the GridBagLayout class always aligns the components in a grid pattern.
  • Each row can be a different height from the other rows, and each column can be a different width from the other columns.
  • All the cells within a given row will be the same height, and all the cells within a given column will be the same width.
  • If the grid pattern is smaller than the frame that contains it, the components will (by default) appear in the middle of the frame, and the extra space will appear around the edges of the grid pattern.
  • A component can occupy more than one cell in the grid pattern.

Now let’s take a closer look at the GridBagConstraints class.

The GridBagConstraints class
The key to understanding GridBagLayout is understanding the GridBagConstraints class. For each component you add to a GridBagLayout, JBuilder will create an associated GridBagConstraints object. The GridBagConstraints class defines 11 constraints, or rules, which the GridBagLayout class uses to position components.

If you’re using something other than JBuilder to program in Java, you must make an instance of a GridBagConstraints object in your application or applet, set the object variables appropriately, then associate the object with a component using GridBagLayout’s setConstraints() method. The setConstraints method then copies the GridBagConstraints object so you can change its contents after the setConstraints call without affecting the component layout.

If you’re coding Java the old-fashioned way, you can reuse one GridBagConstraints object each time you add a component to the layout. However, JBuilder handles this for you and will create a new GridBagConstraints object for each component you place on the GridBagLayout.

Setting or changing the constraints will often affect the sizing and positioning of other components in the layout. To see how they interact, let’s examine the 11 GridBagConstraints fields that control component position. In JBuilder, you’ll use the GridBag Constraints property editor, shown in Figure A, to modify these field values.

Figure A: You’ll use the GridBag Constraints property editor to modify
GridBagConstraints field values.

Figure A

gridx and gridy

The gridx and gridy variables indicate the horizontal and vertical location of the component within the grid. The GridBagConstraints constant RELATIVE indicates that the component should be placed to the right of (for gridx) or below (for gridy) the previous component.

gridheight
The gridheight variable indicates the requested height of the component (in grid cells). Its default value is 1, and its effect will vary depending on the constraints of other objects in the layout. If the number of rows in the layout is less than the gridheight value, the component’s height will be equal to the grid height.

This variable has two special values identified by constants in the GridBagConstraints class: REMAINDER indicates that the component should be the last one in its column (and receive any remaining space). RELATIVE indicates that the component should be the next-to-the-last component in its column.

gridwidth
The gridwidth variable indicates the requested width of the component. Its default value is 1, and it causes the same behavior in regard to width that the gridheight variable does for height.

The constant REMAINDER indicates that the component should be the last one in its row (and receive any remaining space). RELATIVE indicates that the component should be the next-to-the-last component in its row.

weightx and weighty
The weightx and weighty fields determine how the GridBagLayout object will adjust the sizes of rows and columns as the size of the container changes. For example, you can force a two-column grid to display the first column as one-third of the container and the second as the remaining two-thirds. As you might expect, the interaction between the weightx and weighty values of different rows and columns is a bit complex.

To determine how the weightx values will affect the grid pattern, determine the largest weightx value for each column. (The GridBagLayout object will use the largest value for the entire column.) Then, repeat this for each column in the grid. When you have the maximum weightx values from each column, add them together to determine the total weightx of the grid.

Next, determine the default width of the column, which is the width of the widest component in that column. Repeat this for each column, then add the default column width totals to determine the default grid width.

The width of a given column will be equal to the ratio of that column’s weightx and the total weightx for the grid, multiplied by the difference between the width of the container and the default grid width. This means that columns in which all the items have a weightx value of 0.0 won’t be affected by changes in the width of the container. However, the width of columns that have a non-zero weightx value will grow or shrink in proportion to the amount of extra space around the grid cells.

anchor
The anchor variable tells the layout manager how you’d like the component aligned within its cell. The variable has nine possible values, allowing the component to be aligned to any corner, any side, or the center. (If the component isn’t smaller than the cell that contains it, this setting won’t have any effect.)

You can use the GridBagConstraints constants—CENTER (the default), EAST, NORTH, NORTHEAST, NORTHWEST, SOUTH, SOUTHWEST, SOUTHEAST, or WEST—to set the value. Other values will cause the GridBagLayout manager to throw an IllegalArgumentException.

fill
The fill variable indicates how the component should be resized if the grid cell is larger than the default component size. You can use the constant NONE (no resizing), VERTICAL (resize the component to fill the display area vertically, but not horizontally), HORIZONTAL (resize the component to fill the display area horizontally, but not vertically), or BOTH (resize vertically and horizontally) to set the value. The default value is
NONE; invalid values will result in no resizing.

Don’t confuse this with the gridwidth and gridheight fields, which cause a component to span cell boundaries. The fill field merely controls how a component’s size will change when its cell changes size.

insets
The insets variable specifies the amount of space between the component and the top, bottom, left, and right sides of its cell. It defaults to 0 for all sides. This behavior may cause the cell size to increase if the component is already at its minimum size.

ipadx and ipady
The ipadx and ipady variables indicate, respectively, the horizontal and vertical padding of the component beyond its minimum size. The GridBagLayout will multiply each of these values by two and add the products to the minimum horizontal and vertical sizes when laying out the components. One reason to use these variables is to make the default size of a ButtonControl larger than its caption would dictate.

Putting it all together
Because of the number of variables involved and the near-infinite number of ways they can interact with each other, it takes some time to get comfortable with GridBagLayout. Let’s work through a simple example that will illustrate a few of its behaviors.

To begin, create a new applet, and use the Object Inspector to change the frame’s layout property to GridBagLayout. Then, place five ButtonControl components on the applet. Their position isn’t crucial, and depending on where you place them, they’ll align in a grid pattern. Next, open the Source view of the applet and modify the applet’s jbInit() method to resemble the one shown in Listing A. (We’ve highlighted in color the code you’ll need to change.)

Listing A: The jbInit() method

public void jbInit() throws Exception{

this.setSize(new Dimension(335, 237));

buttonControl1.setLabel("buttonControl1");

buttonControl2.setLabel("buttonControl2");

buttonControl3.setLabel("buttonControl3");

buttonControl4.setLabel("buttonControl4");

buttonControl5.setLabel("buttonControl5");

this.setLayout(gridBagLayout1);

this.add(buttonControl1,

new GridBagConstraints2(0, 0, 1, 1,

0.0, 0.0,

GridBagConstraints.CENTER,

GridBagConstraints.VERTICAL,

new Insets(0, 0, 0, 0), 0, 0));

this.add(buttonControl2,

new GridBagConstraints2(0, 1, 1, 1,

0.0, 0.0,

GridBagConstraints.CENTER,

GridBagConstraints.NONE,

new Insets(0, 0, 0, 0), 0, 0));

this.add(buttonControl3,

new GridBagConstraints2(1, 0, 1, 1,

0.0, 0.0,

GridBagConstraints.CENTER,

GridBagConstraints.NONE,

new Insets(0, 0, 0, 0), 0, 0));

this.add(buttonControl4,

new GridBagConstraints2(1, 1, 1, 1,

0.0, 0.0,

GridBagConstraints.CENTER,

GridBagConstraints.NONE,

new Insets(0, 0, 0, 0), 0, 0));

this.add(buttonControl5,

new GridBagConstraints2(2, 0, 1, 1,

0.0, 0.0,

GridBagConstraints.CENTER,

GridBagConstraints.NONE,

new Insets(0, 0, 0, 0), 0, 0));

}

Now, display the Design view of the applet. The arrangement of the ButtonControl components should resemble Figure B.

Figure B: The initial arrangement of the ButtonControl components is a simple grid.

Figure B

In the source code in Listing A, we’ve basically set the gridx and gridy fields of the GridBagConstraints objects that correspond to each ButtonControl object; the values we’ve chosen will align the buttons in a two-row, three-column grid. Initially, the cells of this grid are exactly the same size as the ButtonControl objects. The GridBagLayout object forces the components to the center, and any extra space (unused container real estate) appears around the edges of the grid.

Next, select buttonControl5, and modify its constraints property by double-clicking on that value in the Object Inspector. When the Constraints property editor window appears, set the Grid Position Height value to 2 and select the S radio button in the Anchor group. Click OK to save the new constraint values.

When the Constraints property editor closes, you’ll see that buttonControl5 now appears to be in a new position. In fact, it’s still at position 2,0 in the grid—but it now occupies both cell 2,0 and cell 2,1. Since the anchor constraint is now SOUTH, the ButtonControl appears at the bottom of its new display region.

Reopen the Constraints property editor for buttonControl5, and select the Vertical radio button in the Fill group. Click OK to save the new constraint value.

Now you’ll notice that buttonControl5 occupies the entire third column. This happens because the gridheight constraint value for this ButtonControl is still 2, but since we changed the fill constraint to VERTICAL, the layout manager resized the component to be as tall as the height of two rows.

Return to the applet’s Source view, then modify the jbInit() method as shown in color in Listing B. (You’ll be changing the weightx and fill constraints for the first three ButtonControl objects.)

Listing B: Revised jbInit() fragment

this.add(buttonControl1,

new GridBagConstraints2(0, 0, 1, 1,

1.0, 0.0,

GridBagConstraints.CENTER,

GridBagConstraints.NONE,

new Insets(0, 0, 0, 0), 0, 0));

this.add(buttonControl2,

new GridBagConstraints2(0, 1, 1, 1,

2.0, 0.0,

GridBagConstraints.CENTER,

GridBagConstraints.HORIZONTAL,

new Insets(0, 0, 0, 0), 0, 0));

this.add(buttonControl3,

new GridBagConstraints2(1, 0, 1, 1,

1.0, 0.0,

GridBagConstraints.CENTER,

GridBagConstraints. HORIZONTAL,

new Insets(0, 0, 0, 0), 0, 0));

Return to Design view, click on the container background, and make the container much wider. As you resize the container, you’ll notice that the widths of the first two columns will change; the first widens twice as much as the second, as shown in Figure C.

Figure C: Changing the weightx and fill constraints of a few components can dramatically affect the appearance of the entire layout.

Figure C

Finally, return to the applet’s Source view and make the changes to the jbInit() method that appear in Listing C. (We’ve highlighted the changes in color.)

Listing C: Third version of jbInit()

this.add(buttonControl1,

new GridBagConstraints2(0, 0, 1, 1,

0.0, 0.0,

GridBagConstraints.CENTER,

GridBagConstraints.NONE,

new Insets(0, 0, 0, 0), 0, 0));

this.add(buttonControl2,

new GridBagConstraints2(0, 1, 1, 1,

0.0, 0.4,

GridBagConstraints.CENTER,

GridBagConstraints.VERTICAL,

new Insets(0, 0, 0, 0), 0, 0));

this.add(buttonControl3,

new GridBagConstraints2(0, 2, 1, 1,

0.0, 0.1,

GridBagConstraints.CENTER,

GridBagConstraints.VERTICAL,

new Insets(0, 0, 0, 0), 0, 0));

this.add(buttonControl4,

new GridBagConstraints2(0, 3, 1, 1,

0.0, 0.0,

GridBagConstraints.CENTER,

GridBagConstraints.NONE,

new Insets(0, 0, 0, 0), 0, 0));

this.add(buttonControl5,

new GridBagConstraints2(1, 0,

GridBagConstraints.REMAINDER,

GridBagConstraints.REMAINDER,

1.0, 0.0,

GridBagConstraints.CENTER,

GridBagConstraints.BOTH,

new Insets(0, 0, 0, 0), 0, 0));

Return to the applet’s Design view. There, you’ll see that the ButtonControl objects are in dramatically different positions and have changed size, and have new constraints on their movement, as shown in Figure D.

Figure D: The new constraints greatly alter the applet’s appearance and behavior.

Figure D

Conclusion

In this article, we’ve covered the basics of the GridBagLayout and GridBagConstraints classes and discussed how JBuilder uses them to lay out the components in a container. GridBagLayout is always full of surprises, however. To get comfortable with this class, you should spend a few hours playing with it. Simply modify constraints one at a time and observe the effect on the component, as well as all the other components in the layout. Once you’ve mastered GridBagLayout, you’ll find it a valuable tool for laying out dynamic user interfaces that must look good on a variety of platforms.


Tom Mitchell is co-author of Professional Java Fundamentals, published by WROX Press. He's a senior product developer at The Molloy Group. You can reach him at tjmitch@nac.net.

Tim Gooch is Editor-in-Chief of JBuilder Developer's Journal as well as several other journals published by ZD Journals. You can reach him at jbuilder_dev@cobb.com.


Back to Top
Back to Index of Articles

Copyright © 1997, ZD Journals, a division of Ziff-Davis Inc. ZD Journals and ZD Jounals logo are trademarks of Ziff-Davis Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis is prohibited.
Trademarks & Copyright © 1998 INPRISE Corporation.