Skip to main content

Swing and Roundabouts 4: Grid Bag Grease

Posted by evanx on July 27, 2006 at 6:02 AM PDT

layout1_200.jpg

Ethan Nicholas blogged recently on "Reinventing GridBagLayout", which enjoyed many comments regarding simplifying GBL, and problems with GBL. Karsten Lentzsch notes that "SpringLayout is very powerful, ExplicitLayout is powerful, FormLayout is quite powerful, HIGLayout is quite powerful, GBL is weak." He compares layout managers at the end of his Forms whitepaper.

We hear that Netbean's Matisse GroupLayout is state-of-the-art. It does seem to have a learning curve, for hand coding. So i haven't got around to trying it yet. Anyway, my requirements are not very stringent, and so i still just use GridBagLayout, which is my layout comfort zone. I use spacer panels ie. with fill not NONE, and assemble subpanels, and get what i want without any constraints, i mean complaints.

Cay Horstmann introduced "GBC.java - a convenience class to tame the GridBagLayout" (2002) in Core Java. That must have leaked out of my subconscious at some point, and led to me to implement a similar friendly extension of GridBagConstraints, as follows.

public class Gbc extends GridBagConstraints {

    public Gbc(int gridx, int gridy, int anchor, int fill, Insets insets) {
        super(gridx, gridy, 1, 1, 0., 0., NORTHWEST, NONE, new Insets(0, 0, 0, 0), 0, 0);
        anchor(anchor);
        fill(fill);
        insets(insets);
    }

    public Gbc(int gridx, int gridy, Insets insets) {
        this(gridx, gridy, 0, 0, insets);
    }

    public Gbc(int gridx, int gridy) {
        this(gridx, gridy, 0, 0, null);
    }

    public Gbc insets(Insets insets) {
        if (insets == null) insets = new Insets(0, 0, 0, 0);
        this.insets = insets;
        return this;
    }

    public Gbc anchor(int anchor) {
        if (anchor == 0) anchor = NORTHWEST;
        this.anchor = anchor;
        return this;
    }

    public Gbc fill(int fill) {
        if (fill == 0) fill = NONE;
        if (fill == HORIZONTAL || fill == BOTH) weightx = 1;
        if (fill == VERTICAL || fill == BOTH) weighty = 1;
        this.fill = fill;
        return this;
    }

    public Gbc none() {
        return fill(NONE);
    }

    public Gbc both() {
        return fill(BOTH);
    }

    public Gbc vertical() {
        return fill(VERTICAL);
    }

    public Gbc horizontal() {
        return fill(HORIZONTAL);
    }

    public Gbc center() {
        return anchor(CENTER);
    }

    public Gbc north() {
        return anchor(NORTH);
    }

    public Gbc northeast() {
        return anchor(NORTHEAST);
    }

    public Gbc east() {
        return anchor(EAST);
    }

    public Gbc southeast() {
        return anchor(SOUTHEAST);
    }

    public Gbc south() {
        return anchor(SOUTH);
    }

    public Gbc southwest() {
        return anchor(SOUTHWEST);
    }

    public Gbc west() {
        return anchor(WEST);
    }

    public Gbc northwest() {
        return anchor(NORTHWEST);
    }

    public Gbc top(int top) {
        insets.top = top;
        return this;
    }

    public Gbc bottom(int bottom) {
        insets.bottom = bottom;
        return this;
    }

    public Gbc right(int right) {
        insets.right = right;
        return this;
    }

    public Gbc left(int left) {
        insets.left = left;
        return this;
    }

    public Gbc insets(int top, int left, int bottom, int right) {
        insets = new Insets(top, left,  bottom, right);
        return this;
    }

    public Gbc cloneGbc() {
        Gbc gbc = (Gbc) clone();
        gbc.insets = (Insets) insets.clone();
        return gbc;
    }

    public static String formatGbcValue(int value) {
        if (value == NONE) return "NONE";
        if (value == HORIZONTAL) return "HORIZONTAL";
        if (value == VERTICAL) return "VERTICAL";
        if (value == BOTH) return "BOTH";
        if (value == NORTH) return "NORTH";
        if (value == NORTHEAST) return "NORTHEAST";
        if (value == EAST) return "EAST";
        if (value == SOUTHEAST) return "SOUTHEAST";
        if (value == SOUTH) return "SOUTH";
        if (value == SOUTHWEST) return "SOUTHWEST";
        if (value == WEST) return "WEST";
        if (value == NORTHWEST) return "NORTHWEST";
        if (value == CENTER) return "CENTER";
        return "gbcValue=" + value;
    }

    public String toString() {
        StringBuffer buffer = new StringBuffer("Gbc");           
        buffer.append(" x" + gridx);
        buffer.append(" y" + gridy);
        buffer.append(" " + formatGbcValue(anchor));
        buffer.append(" " + formatGbcValue(fill));
        buffer.append(" " + insets.toString());
        return buffer.toString();
    }           
}

where i use weights that are either 0.0 or 1.0, depending on the fill.

Feel free to use and abuse this class as you wish. You can find it via http://java.net/projects/gridbaglady, under the ASL.

The screenshot below, of the source of the above, shows Gbc.java in action.

As a further example, the following code uses Gbc to create a simple button panel, as used for the above demo.

public JPanel createButtonPanel(NAction ... actions) {
        JPanel panel = new JPanel(new GridBagLayout());
        int index  = 0;
        for (NAction action : actions) {
            panel.add(new JButton(action), new Gbc(index, 0).right(4));
            index++;
        }
        return panel;
    }
}

where the right inset is given as 4, to space the buttons apart.

Related Topics >>