While working on a desktop project (which I hope to release a preview applet/jnlp soon) I decided to use a LayoutManager. Java provides many layout managers whose intention is to layout your controls (buttons, checkboxes, labels, etc) without setting sizes and positions. This post is introducing the GridBagLayout layout manager and why I choose to use this one over the others.
Reasoning
1. GridBagLayout is easy to program by hand. The Java tutorials released by Sun recommend that when using this layout manager that you should use a GUI builder. I don’t really agree with this since its so easy to understand.
2. GridBagLayout does what I want. Some of the other layout managers will layout the controls in the manner that I want. However, the problem comes in when the container of the controls is resized. Most of the layout managers will attempt to resize the controls, which I’m ok with it when the container is resized smaller, but when the container is resized larger than needed then the controls start to resize also, which in my opinion looks really stupid. GridBagLayout, which you will see later in the post, has the ability to stop this behavior.
3. GridBagLayout is similar to table layouts in HTML. When you work in web development you see sites and forms laid out using tables. Using tables for form layout is very common and accepted since table layouts provide control for alignment both horizontally and vertically and naturally align columns of labels and controls. GridBagLayout has a similar feel, you create your controls tell it what column/row you want it to be in and thats it.
How To
To use GridBagLayout is very simple.
First set the layout of your container:
JFrame frame = new Frame("Test"); frame.setLayout(new GridBagLayout());
Next create a few controls:
JLabel lblTest = new JLabel("Test label"); JButton btnTest = new JButton("Do Nothing");
Lastly add the controls to the container (this is where we actually specify where the controls appear in the layout):
// first create a constraint for the control GridBagContraints clbl = new GridBagContraints( 0, // the column 0, // the row 1, // the column span 1, // the row span 1, // the weight x 0, // the weight y GridBagConstraints.FIRST_LINE_START, // the alignment GridBagConstraints.NONE, // what directions to stretch the control null, // the insets 0, // padding x 0 // padding y ); // now add the control to the container using the constraint frame.add(lblTest, clbl);
The keys to this layout manager are in the GridBagConstraints. First, the column/row span parameters can actually be GridBagConstraints.REMAINDER which means, take up the remaining columns/rows. This allows an arbitrary number of columns or rows that doesn’t require predefinition. Second, the alignment in the “cell” can be used to align a column all to the left or right without worrying how big the controls are or the fonts they use. Lastly, the fact that this layout will allow the controls NOT to be resized via the GridBagConstraints.NONE parameter. In addition, the fact that all of the controls and the container itself do not need set sizes makes this a very robust layout.
Let me just say a few more things about the parameters to GridBagConstraints. The weight parameters are used to say that the “cell” that I’m defining will stretch with the layout. If used with GridBagConstraints.NONE, the “cell” will grow/shink with the container (but the control will not). If the weight of all the controls on the layout are the same, the layout, when the container is stretched, will evenly space the controls between the entire height/width of the container. To avoid this, set all the control’s weights to 0 unless they are the last column/row, in which case set them to 1. This will only stretch the “cells” that are the last row or last column and therefore keep the controls at the same spacing even though the container has been resized.
Here is a full example of what I was trying to create:
import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextPane; public class Test extends JFrame { public Test() { super("Test"); // set the close operation this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // set the layout this.setLayout(new GridBagLayout()); // create some insets; these can be reused Insets insets = new Insets(2, 2, 2, 2); // create some controls JLabel lblTest = new JLabel("Test label"); JButton btnTest = new JButton("Do Nothing"); JTextPane panTest = new JTextPane(); // create some constraints // i want this one to be at 0,0 GridBagConstraints clbl = new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.NONE, insets, 0, 0); // i want this one to be at 1,0 and to stretch with the container // along the x axis GridBagConstraints cbtn = new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.NONE, insets, 0, 0); // i want this one to be at 0,1 and to stretch with // the container along the x and y axes and span two columns // and grow with the cell GridBagConstraints cpan = new GridBagConstraints(0, 1, 2, 1, 1, 1, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH, insets, 0, 0); // add the controls to the container this.add(lblTest, clbl); this.add(btnTest, cbtn); this.add(panTest, cpan); // tell the layout to size itself this.pack(); } public static void main(String[] args) { // create the frame Test t = new Test(); // show the frame t.setVisible(true); } }