Wednesday, August 13, 2008

GridBag, Dude...

If you've ever done Swing programming, you've likely had this experience.
GridBagLayout is one of the more complicated layout managers, but as with most complicated things, it gives you a lot of power and flexibility.

GridBag gets its power from a set of GridBagConstraints provided with each Component you add to the layout. The GridBagConstraint attributes we are interested in are:
  • gridx & gridy : These attributes set the x and y coordinates in the grid that you want the component to appear in.

  • gridwidth & gridheight : These attributes set the number of grid cells the component should take up.

  • anchor : The side or corner you want the Component to attach to.

Now, keeping those constraint attributes in mind, let's see if that dialog could be made to work. For a starting point, we'll use the code as entered in the animation (with a few assumptions)

public class TotallyGridBag {
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() { buildAndShowGui(); }
});
}

static void buildAndShowGui() {
JFrame frame = new JFrame("Totally GridBag");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());

JComboBox colors = new JComboBox(new String[]{"Red", "Blue", "Green", "Yellow"});

// Constraints for left column
GridBagConstraints left = new GridBagConstraints();
left.anchor = NORTHEAST;
left.gridx = 0;

// Constraints for right column
GridBagConstraints right = new GridBagConstraints();
right.anchor = NORTHWEST;
right.gridx = 1;

frame.add(new JLabel("Name"), left);
frame.add(new JTextField(10), right);
frame.add(new JLabel("Age"), left);
frame.add(new JTextField(3), right);
frame.add(new JLabel("Favorite Color"), left);
frame.add(colors, right);

JPanel buttons = new JPanel();

// Constraints for button panel
GridBagConstraints gbc2 = new GridBagConstraints();
gbc2.anchor = SOUTHEAST;
gbc2.gridx = 0;
gbc2.gridwidth = REMAINDER;

buttons.add(new JButton("OK"));
buttons.add(new JButton("Cancel"));

frame.add(buttons, gbc2);

frame.pack();
frame.setLocation(200, 200);
frame.setVisible(true);
}
}

As you saw in the animation, this mostly works and results in the following layout.



The only major issue is the text fields resizing to zero width when the window gets too small. The buttons could also use some spacing.

Fixing the button spacing is as simple as adding some horizontal glue between the buttons to take up space.

To fix the text fields, we have three options.
  1. Set the fill attribute on the right constraint. This will tell the layout manager to set the widths of the text fields so they fill the column. Doing this prevents the fields from dropping to zero width, but will resize the name field to the same width as age when the window gets too narrow




  2. Set the minimum size of the text fields after the frame has been packed. This prevents the layout manager from resizing the name field smaller than the minimum columns we specified, but results in the text field spilling off the frame.




  3. Set the minimum size of the frame after it has been packed. This is probably the best choice if we want to keep the entire layout as a GridBag. It keeps the preferred sizes we set on the text fields and prevents the frame from being shrunk below the minimum size needed to lay out the components.

...
frame.pack();

frame.setMinimumSize(frame.getSize());

frame.setLocation(200, 200);
frame.setVisible(true);
...

Next time, I'll take a look at GroupLayout and FormLayout, two layout managers designed to make setting up this type of layout easier.

Tuesday, August 12, 2008

Format Testing

Testing SyntaxHighlighter Prettify. Actual content will be forthcoming.

code:
import java.util.List;
public class CommonUtils {
@SuppressWarnings("unsafe")
public static <T> List<T> coerce(List list){
return (List<T>) list;
}
}


pre:
import java.util.List;
public class CommonUtils {
// Coerces a List to a List
@SuppressWarnings("unsafe")
public static <T> List<T> coerce(List list){
return (List<T>) list;
}
}