HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

My last column focused on several of Java's LayoutManagers, which are constructs used by developers to position Components within Containers using logic instead of pixel coordinates. We discussed all of Java's LayoutManagers except GridBagLayout, which is the focus of this article.

Of all of Java's LayoutManagers, GridBagLayout offers the developer the most precision in positioning Components. This ability comes at a great expense, as GridBagLayout is the most complicated (and probably the most poorly documented) LayoutManager in the AWT. GridBagLayout works integrally with a helper class called GridBagConstraints to place Components on the screen. Basically, a developer will set values in the GridBagConstraints object that specify things such as:

  • Where the component will appear on the screen in relation to the other Components
  • How tall and wide the component is
  • How the component grows when the container resizes

A method provided in GridBagLayout will bind the constraints to a particular Component. When the Component is added to the Container (using the add method), GridBagLayout will use the information in the Components corresponding GridBagConstraints object to determine the Component's position and size.

In short, the process is:

  1. Create Component
  2. Set GridBagConstraints for Component
  3. Bind Component and GridBagConstraints object
  4. Add Component
Most of the work involved in using GridBagLayout is setting the constraints correctly.

As the name implies, GridBagLayout has something to do with a grid (and a bag). GridBagLayout is similar to GridLayout in the following regards:

  • The Container is divided into a grid.
  • Components are added to the cells of the grid.
The differences between GridLayout and GridBagLayout are more striking:
  • Components do not necessarily fill their entire cell.
  • All cells are not of equal size, meaning that all columns do not necessarily have the same number of cells, and all rows do not necessarily have the same number of cells.
Also, GridBagLayout offers no methods to explicitly define the number of rows or columns in the grid, nor does it have methods to define the size of each cell in the grid. Instead, GridBagLayout calculates the number of rows and columns in a grid by the number of Components placed on the screen. If a container has five Components lined up horizontally, then the grid consists of five columns and one row. If the Container has five Components lined up vertically, then the grid consists of one column and five rows. So how do you know how many columns and rows your GUI will have? Well, the best way is to hand draw your gui and create the grid for yourself. Figure 1 shows a standard source/destination kind of gui. Note the dashed lines and numbers. We have gone along the X axis and made a mark when we came into contact with the upper-left hand corner of a Component. We have done the same thing along the Y axis. Keep in mind when you do this on your own that you should mark only the upper left hand corner of the Component. After the exercise is complete, you are left with the grid your GridBagLayout will use to place Components.

Figure 1
Figure 1:

Once the grid is complete, we have some very important pieces of information; the upper left hand coordinate of each Cell, and the width and height of each Cell. GridBagConstraints has data members that maintain this information and need to be set for the gui to work. The data members are: gridx, gridy, gridwidth and gridheight. Look at Figure 2 to see the cells of the grid and Table 1 to see the GridBagConstraints attributes for each Component.

Figure 2
Figure 2:
Table 1

In our program, we have created a helper method, addComponent, to assist in setting the constraints. Notice that we do not have to create a new GridBagConstraints object every time we add a Component. Also notice the sequence of events: First we set constraints, then we bind the constraints to the Component using the setConstraints method and finally we add the Component. Be sure to do things in this order to avoid confusion! Look at Listing 1 for the complete code listing. And congratulations! If you can get this far, you have done the hard part.

Once the program has been compiled and executed we find that the results are not quite the same as our intention. The code needs some refinement. Look at Figure 3 for the output of the program. Notice that the four buttons in the center are not aligned, and everything is squished together in the center of the screen. The remaining tasks involve setting more constraints attributes on each Component.

Figure 3
Figure 3:

GridBagConstraints.fill
The default value for the fill is NONE, meaning that a Component will not grow to fill its entire cell if there is extra space available in the cell. Look at the > button and the >> button. The width of the column is the width of the >> button (column width is always the width of the widest cell in the column). Using the fill attribute, we can specify that a Component will fill in one of four ways:

  • GridBagConstraints.VERTICAL - The Component will grow taller, but not wider.
  • GridBagConstraints.HORIZONTAL - The Component will grow wider, but not taller.
  • GridBagConstraints.BOTH - The Component will grow both vertically and horizontally
  • GridBagConstraints.NONE - The Component will not grow to fill extra cell space.
GridBagConstraints.anchor
The anchor attribute specifies where in the cell the component will be placed. The default value is CENTER. Other values are: NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST and NORTHWEST. Look at Figure 4 and the code snippet in Listing 2 to see what happens to the labels and OK and Cancel buttons when the anchors are adjusted. Note that if the fill is set to BOTH, setting the anchor is pretty meaningless.

Figure 4
Figure 4:

GridBagConstraints.weightx and GridBagConstraints.weighty
If you have taken the time to type in the code provided in Listing 2 and played around with the resulting Frame, you will have noticed that regardless of the size of the frame, the Components cluster in the middle of the Container and donŐt resize when the Frame resizes. Ascribing a weight to a Component will allow the Components cell to grow or shrink with the Container. Keep in mind that it is only the cell size that changes, not the Component in the cell. The default value for weightx and weighty is zero, meaning that extra space in the Container will not be absorbed by a cell. A non-zero weightx indicates the ratio describing how extra space will be distributed among horizontally neighboring cells. For example, if the OK button has a weightx of 2, and the Cancel button has a weightx of 1, when the Frame is made wider, the OK ButtonŐs cell will receive 2 pixels for every one received by the Cancel Button. The same is true for weighty neighbors. In general, the greater the weight, the more space the cell will receive.

Note also that weights affect the cell size, not the Component size. Here is where some of the other attributes of GridBagConstraints will play an important role. If the fill is set to something other than NONE, and a cell has a non-zero weight, the Component itself will grow to fill any newly acquired space in the cell. Alternatively, if an anchor is set to something other than CENTER, and a cell has a weight other than zero, the positioning of a Component within a cell will be more apparent. Play around with it!

GridBagConstraints.insets
Insets add a border of a fixed pixel size to the inner perimeter of the cell. Adding insets may make the size of the Component shrink.

GridBagConstraints.ipadx and GridBagConstraints.ipady
ipadx and ipady (internal padding x and internal padding y ) will add a fixed number of pixels to the width and height of a component. They will make the size of the Component larger. See Figure 5 to see the differences between insets and internal padding.

Figure 5
Figure 5:

GridBagLayout Tips
Once you successfully develop a screen using GridBagLayout, you may want to change it later. This will be difficult if you have used consecutive numbers for your gridx and gridy values. For example, if you wanted to squeeze another Component in between the add Button and the addAll Button, you would have to enter new gridy values for all of the Components appearing below the new Component. Instead, it is a good practice to make your gridx and gridy values multiples of 10. Instead of column numbers being 1,2,3 they should be 10,20,30. The same is true for rows. A co-worker has noticed that this is also a good practice in defining line numbers for BASIC programming.

I have not discussed GridBagConstraints.RELATIVE and GridBagConstraints.REMAINDER. Don't use them until you read my next column! As with any other topic in programming, the best way to learn it is to play around with the code, so please do so.

About the Author
John V. Tabbone is a lecturer at New York University's Information Technologies Institute, where he teaches two Java programming courses and advises on curriculum development. He has been a professional Java programmer since early 1996 and continues to consult on and develop systems for a variety of New York-based businesses. You may e-mail him with questions and comments at [email protected]

	

Listing 1.
  
import java.awt.*;  

public class gbl1  
{  

 List  sourceList;  
 List  destinationList;  
 Button  addButton;  
 Button  addAllButton;  
 Button  removeButton;  
 Button  removeAllButton;  
 Button  OKButton;  
 Button  cancelButton;  
 Label  sourceLabel;  
 Label  destinationLabel;  
 Frame  aFrame;  

 GridBagLayout  gbl;  
 GridBagConstraints gbc;  
   

 public gbl1()  
 {  
  sourceList  = new List();  
  destinationList  = new List();  
  addButton  = new Button( " >" );  
  addAllButton  = new Button( ">>" );  
  removeButton  = new Button( " >" );  
  removeAllButton = new Button( ">>" );  
  OKButton  = new Button( "Ok" );  
  cancelButton  = new Button( "Cancel" );  
  sourceLabel  = new Label( "Source" );  
  destinationLabel = new Label( "Destination" );  
  aFrame   = new Frame();  
  gbl   = new GridBagLayout();  
  gbc   = new GridBagConstraints();  

  aFrame.setLayout( gbl );  
  buildFrame();  
  aFrame.setSize( 300,200 );  
  aFrame.show();  
 }  
   

 public void buildFrame()  
 {  
  addComponent( 0,0,1,1,aFrame,sourceLabel );  
  addComponent( 2,0,1,1,aFrame,destinationLabel );  
  addComponent( 0,1,1,4,aFrame,sourceList );  
  addComponent( 2,1,1,4,aFrame,destinationList );  
  addComponent( 1,1,1,1,aFrame,addButton );  
  addComponent( 1,2,1,1,aFrame,addAllButton );  
  addComponent( 1,3,1,1,aFrame,removeButton );  
  addComponent( 1,4,1,1,aFrame,removeAllButton );  
  addComponent( 0,5,1,1,aFrame,OKButton );    
  addComponent( 2,5,1,1,aFrame,cancelButton );  
 }  
   
 /**  
 * A helper method to add Components to a Container using   
* GridBagLayout  
*/  
public void addComponent( int x, int y, int w, int h, Container aContainer, Component aComponent )  
 {  
  gbc.gridx = x;  
  gbc.gridy = y;  
  gbc.gridwidth = w;  
  gbc.gridheight = h;  
  gbl.setConstraints( aComponent, gbc );  
  aContainer.add( aComponent );  
 }  
  
   

 public static void main( String[] args )  
 {  
  gbl1 myLayout = new gbl1();  
 }  
   

}// end class  

Listing 2.
  
 public void buildFrame()  
 {  
  gbc.anchor = gbc.EAST;  
  addComponent( 0,0,1,1,aFrame,sourceLabel );  
  gbc.anchor = gbc.WEST;  
  addComponent( 2,0,1,1,aFrame,destinationLabel );  
  gbc.anchor = gbc.CENTER;  // back to default  
  addComponent( 0,1,1,4,aFrame,sourceList );  
  addComponent( 2,1,1,4,aFrame,destinationList );  
  addComponent( 1,1,1,1,aFrame,addButton );  
  addComponent( 1,2,1,1,aFrame,addAllButton );  
  addComponent( 1,3,1,1,aFrame,removeButton );  
  addComponent( 1,4,1,1,aFrame,removeAllButton );  
  gbc.anchor = gbc.EAST;  
  addComponent( 0,5,1,1,aFrame,OKButton );   
  gbc.anchor = gbc.WEST;    
  addComponent( 2,5,1,1,aFrame,cancelButton );  
 }  

Listing 3
  
import java.awt.*;  

public class gbl1  
{  

 List  sourceList;  
 List  destinationList;  
 Button  addButton;  
 Button  addAllButton;  
 Button  removeButton;  
 Button  removeAllButton;  
 Button  OKButton;  
 Button  cancelButton;  
 Label  sourceLabel;  
 Label  destinationLabel;  
 Frame  aFrame;  

 GridBagLayout  gbl;  
 GridBagConstraints gbc;  
   

 public gbl1()  
 {  
  sourceList  = new List();  
  destinationList  = new List();  
  addButton  = new Button( " >" );  
  addAllButton  = new Button( ">>" );  
  removeButton  = new Button( " >" );  
  removeAllButton = new Button( ">>" );  
  OKButton  = new Button( "Ok" );  
  cancelButton  = new Button( "Cancel" );  
  sourceLabel  = new Label( "Source" );  
  destinationLabel = new Label( "Destination" );  

  sourceLabel.setAlignment ( Label.CENTER );  
  destinationLabel.setAlignment ( Label.CENTER );  
  aFrame    = new Frame();  
  gbl    = new GridBagLayout();  
  gbc    = new GridBagConstraints();  

  aFrame.setLayout( gbl );  
  buildFrame();  
  aFrame.setSize( 300,200 );  
  aFrame.show();  
 }  

 public void buildFrame()  
 {    
 addComponent(0,0,1,1,gbc.HORIZONTAL,1,1,aFrame,sourceLabel);  
 addComponent(2,0,1,1,gbc.HORIZONTAL,1,1,aFrame,destinationLabel );  
  addComponent( 0,1,1,4,gbc.BOTH,10,10,aFrame,sourceList );  
  addComponent( 2,1,1,4,gbc.BOTH,10,10,aFrame,destinationList );  
  addComponent( 1,1,1,1,gbc.NONE,1,1,aFrame,addButton );  
  addComponent( 1,2,1,1,gbc.NONE,1,1,aFrame,addAllButton );  
  addComponent( 1,3,1,1,gbc.NONE,1,1,aFrame,removeButton );  
  addComponent( 1,4,1,1,gbc.NONE,1,1,aFrame,removeAllButton );    
  addComponent( 0,5,1,1,gbc.HORIZONTAL,0,2,aFrame,OKButton );   
  addComponent( 2,5,1,1,gbc.HORIZONTAL,0,2,aFrame,cancelButton );  
 }  

public void addComponent
( int x, int y, int w, int h, int fill, int xWeight, int yWeight, Container aContainer, Component aComponent )  
 {  
  gbc.gridx = x;  
  gbc.gridy = y;  
  gbc.gridwidth = w;  
  gbc.gridheight = h;  
  gbc.fill = fill;  
  gbc.weightx = xWeight;  
  gbc.weighty = yWeight;  
  gbl.setConstraints( aComponent, gbc );  
  aContainer.add( aComponent );  
 }  
  
   

 public static void main( String[] args )  
 {  
  gbl1 myLayout = new gbl1();  
 }  
   

}// end class
  
      
 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.