AT&T Home | AT&T Labs | Research
AT&T Labs, Inc. - Research

The Yoix® Scripting Language

Home | What's New | Grammar | Documentation | Download | License | YChart | YDAT | YWAIT | Byzgraf | FAQs
GridBagLayout typedict
 
A GridBagLayout is a layout manager that arranges the components in a container based on GridBagConstraints or other objects (e.g., special integer constants or doubles) that appear in the container's layout array. Components should be AWT or Swing components, however all layout managers build a label appropriate for the container they are working on when they find a String in the layout array where they expected a component. Properties, like the font or foreground color, used by these short-hand labels can not be directly specified, so they are inherited from the container.

The organization of the container's layout array that is easiest to explain and always works is the one in which every AWT or Swing component in the array is immediately followed by a new GridBagConstraints object. However another style that is now supported can sometimes lead to compact descriptions of a container's layout. In this style the Java code that examines the layout array allocates and reuses one or more internal GridBagConstraints and decides what to do when it finds an unexpected object, like an int, double, or Dictionary. Components are automatically associated with a column and the internal GridBagConstraints allocated for that column is used unless the entry that follows the component in the layout array is a GridBagConstraints.

No matter which style is used, the end result is that the container is divided into a rectangular grid of cells that do not necessarily have the same properties, and each component is placed in the cells selected by its constraint. The GridBagConstraints also include fields that control what happens to cells and the components in those cells when the container is resized.

The fields in a GridBagLayout are:
columns An int that can be used to specify the number of columns in the grid, but it only applies to the internally allocated GridBagConstraints. In other words, components that are immediately followed by their own GridBagConstraints in the layout array are not affected by columns.

Assigning a positive integer to columns tells the low level Java code that processes the layout array that it should allocate that many internal GridBagConstraints and the last one should have its gridwidth field permanently set to REMAINDER, which automatically ends the current row whenever it is used. Components that are associated with a particular column can reuse the GridBagConstraints that was allocated for that column, which means they inherit properties, like the alignment, that can be set when the first component is put in the column and never mentioned again.

When columns is 0 (the default) the layout array determines when rows end, and the Java code that processes the layout array allocates a single internal GridBagConstraints that every component can reuse. In other words, when a component uses the internal GridBagConstraints it inherits the settings stored by previous components, unless it explicitly changes them. Components are laid out horizontally and the row continues until there are no more components or the integer constant REMAINDER is found in the layout array.

hgap A double that is 0 by default, that represents a fixed amount of horizontal padding, in units of 72 dots per inch, that is added between all components.
model An int that is 1 (the default) if flexible processing of objects in the container's layout array is enabled and 0 if the processing is strict and only accepts objects organized in pairs that consist of a component and its GridBagConstraints.

This field was occasionally used during our development work, but both styles are now supported when model is 1, so there is no reason why this field should be changed.

orientation An int that should be NONE (the default), HORIZONTAL, VERTICAL, or BOTH, and is used to control direction of the padding added to the container when a double is found in the layout array.

When orientation is HORIZONTAL or VERTICAL a positive double in the layout array means rigid spacing (a strut) in the designated direction, a 0.0 means expandable spacing (glue) that stretches in that direction, and a negative double means rigid spacing that is perpendicular to that direction.

An orientation of NONE or BOTH behaves like HORIZONTAL until a component and its constraint end a row, but at that point any double that precedes the next component in the layout array it is treated as vertical padding. BOTH switches back to HORIZONTAL mode after one double, but NONE waits for the next component.

type A read-only int that is set to GRIDBAGLAYOUT, which is defined in yoix.awt and yoix.swing.
vgap A double that is 0 by default, that represents a fixed amount of vertical padding, in units of 72 dots per inch, that is added between all components.

A component can be followed by one or more integer constants that set fields in the internal GridBagConstraints associated with that component. Any integer constant that can be assigned to the anchor or fill fields in a GridBagConstraints is allowed. Constants assigned to fill also set the weightx and weighty fields as is summarized below:

Constant     fill         weightx   weighty
--------     ----         -------   -------
BOTH         BOTH            1         1
HORIZONTAL   HORIZONTAL      1         0
VERTICAL     VERTICAL        0         1
NONE         NONE            0         0
Sometimes you need a little more control over the fill, weightx, and weighty fields, so twelve additional constants defined in yoix.awt and yoix.swing, are available and their behavior is summarized below:
Constant                 fill         weightx   weighty
--------                 ----         -------   -------
BOTH_WEIGHTX             BOTH            1         0
BOTH_WEIGHTY             BOTH            0         1
BOTH_WEIGHT_NONE         BOTH            0         0
HORIZONTAL_WEIGHTY       HORIZONTAL      0         1
HORIZONTAL_WEIGHT_BOTH   HORIZONTAL      1         1
HORIZONTAL_WEIGHT_NONE   HORIZONTAL      0         0
NONE_WEIGHTX             NONE            1         0
NONE_WEIGHTY             NONE            0         1
NONE_WEIGHT_BOTH         NONE            1         1
VERTICAL_WEIGHTX         VERTICAL        1         0
VERTICAL_WEIGHT_BOTH     VERTICAL        1         1
VERTICAL_WEIGHT_NONE     VERTICAL        0         0

The only other integer constant that is recognized in the layout array is REMAINDER, which sets the gridwidth field to a value that ends the current row, but it is a temporary change that is not saved in the internal GridBagConstraints. In other words, using REMAINDER to end a row is always allowed, even if columns is positive, but it does not affect what happens in the next row.

You can also take direct control over other the fields in the internal GridBagConstraints, but you have to do it using a Dictionary that explicitly defines the GridBagConstraints fields that you want to set, because if you used a GridBagConstraints none of the values would be saved. In other words, an expression like

new Dictionary {
    int gridx = 1;
    int gridy = 1;
    int weightx = 1;
}
in the layout array sets the gridx, gridy, and weightx fields in the internal GridBagConstraints.

The hgap and vgap fields are convenient when you want to separate components by fixed amounts, but you can also throw a double into the layout array when you need extra spacing. The value assigned to the orientation field and where you put the double in the layout array will determine whether you get horizontal or vertical padding. Remember to include a decimal point in the number, because integers, as we discussed earlier, mean something completely different.

The GridBagLayout is a powerful layout manager, and it is the one we use most, but it can take time to master. Part of the trouble, at least from our experience, is that properties assigned to a component using GridBagConstraints can affect other components, particularly if those properties need to be propagated horizontally or vertically to other cells in the grid. Despite the difficulty, the GridBagLayout is an indispensable tool, so spend the time to learn it, but you probably should start by trying to master the layout style in which every component is followed by its own GridBagConstraints.
 
 Example:   The program,
import yoix.*.*;

JFrame f = {
    Insets border = {
        double top = 72.0/8;
        double left = 72.0/4;
        double bottom = 72.0/8;
        double right = 72.0/4;
    };

    Dimension size = {
        double width = 10*72;
        double height = 5*72;
    };

    Point location = {
        double x = (VM.screen.width - size.width)/2;
        double y = (VM.screen.height - size.height)/4;
    };

    GridBagLayout layoutmanager;
    Array layout = {
        new JLabel {
            String text = "A Big Red Label";
            String font = "Dialog-bold-16";
            Color  foreground = Color.red;
        },
        new GridBagConstraints {
            int gridwidth = REMAINDER;
        },

        new JTextArea {
            String tag = "$_textarea";
            String font = "Monospaced-plain-12";
            int    scroll = AS_NEEDED;
            int    edit = TRUE;
        },
        new GridBagConstraints {
            int gridwidth = REMAINDER;
            int weightx = 1;
            int weighty = 1;
            int fill = BOTH;
        },

        new JPanel {
            GridLayout layoutmanager;
            Array layout = {
                new JButton {
                    String text = "Update";

                    actionPerformed(e) {
                        String text = date() + "\n";

                        appendText(root.components.$_textarea, text);
                    }
                },
                new JButton {
                    String text = "Clear";

                    actionPerformed(e) {
                        root.components.$_textarea.text = "";
                    }
                },
                new JButton {
                    String text = "Dismiss";

                    actionPerformed(e) {
                        exit(0);
                    }
                },
            };
        },
        new GridBagConstraints {
            int gridwidth = REMAINDER;

            Insets insets = {
                double top = 72.0/8;
            };
        },
    };
};

f.visible = TRUE;
is a simple example that uses standard GridBagLayout techniques and here is the same screen, rewritten to use some of the new layout techniques allowed when the model field is non-zero:
import yoix.*.*;

JFrame f = {
    Insets border = {
        double top = 72.0/8;
        double left = 72.0/4;
        double bottom = 72.0/8;
        double right = 72.0/4;
    };

    Dimension size = {
        double width = 10*72;
        double height = 5*72;
    };

    Point location = {
        double x = (VM.screen.width - size.width)/2;
        double y = (VM.screen.height - size.height)/4;
    };

    GridBagLayout layoutmanager = {
        int columns = 1;
    };
    Array layout = {
        new JLabel {
            String text = "A Big Red Label";
            String font = "Dialog-bold-16";
            Color  foreground = Color.red;
        },
        NONE,

        new JTextArea {
            String tag = "$_textarea";
            String font = "Monospaced-plain-12";
            int    scroll = AS_NEEDED;
            int    edit = TRUE;
        },
        BOTH,

        72.0/8,    // vertical padding

        new JPanel {
            GridLayout layoutmanager;
            Array layout = {
                new JButton {
                    String text = "Update";

                    actionPerformed(e) {
                        String text = date() + "\n";

                        appendText(root.components.$_textarea, text);
                    }
                },
                new JButton {
                    String text = "Clear";

                    actionPerformed(e) {
                        root.components.$_textarea.text = "";
                    }
                },
                new JButton {
                    String text = "Dismiss";

                    actionPerformed(e) {
                        exit(0);
                    }
                },
            };
        },
        NONE,
    };
};

f.visible = TRUE;
Notice how we use the integer constants BOTH and NONE to implicitly reset the fill, weightx, and weighty, fields for the three components that were added to the JFrame's layout array. We encourage you to experiment with these scripts. For example, can you explain what happens when you remove NONE from the button panel in the last example?

In practice we usually use the original GridBagLayout style for top-level containers, like a JFrame or JDialog, but we often choose the new style to describe the layout in a JPanel. Here is a script,

import yoix.*.*;

JDialog screen = {
    Dimension size = NULL;
    String    font = "Dialog-bold-12";
    double    border = 72.0/8;
    int       modal = TRUE;

    GridBagLayout layoutmanager;
    Array layout = {
        new JLabel {
            String text = "Example Login Screen";
            String font = "Dialog-bold-16";
            Color  foreground = Color.red;
        },
        new GridBagConstraints {
            int gridwidth = REMAINDER;
        },

        new JPanel {
            GridBagLayout layoutmanager = {
                int    columns = 2;
                double vgap = 72.0/32;
            };

            Array layout = {
                "Username",
                RIGHT,
                new JTextField {
                    String tag = "$_username";
                    int    columns = 10;
                    int    requestfocus = TRUE;

                    textValueChanged(e) {
                        root.components.$_failed.text = "";
                    }
                },
                LEFT,

                "Password",
                new JTextField {
                    String tag = "$_password";
                    int    columns = 10;
                    int    echo = '*';

                    textValueChanged(e) {
                        root.components.$_failed.text = "";
                    }
                },

                "Group",
                new JTextField {
                    String tag = "$_group";
                    int    columns = 10;

                    textValueChanged(e) {
                        root.components.$_failed.text = "";
                    }
                },
            };
        },
        new GridBagConstraints {
            int gridwidth = REMAINDER;
            int ipadx = 3.0*72;

            Insets insets = {
                double top = 72.0/4;
            };
        },

        new JLabel {
            String tag = "$_failed";
            Color  foreground = Color.red;
        },
        new GridBagConstraints {
            int gridwidth = REMAINDER;
            int weighty = 1;

            Insets insets = {
                double top = 72.0/4;
                double bottom = 72.0/4;
            };
        },

        new JPanel {
            GridLayout layoutmanager;
            Array layout = {
                new JButton {
                    String text = "OK";

                    actionPerformed(e) {
                        root.Login();
                    }
                },

                new JButton {
                    String text = "Quit";
                    Color  foreground = Color.red;

                    actionPerformed(e) {
                        exit(0);
                    }
                },
            };
        },
        new GridBagConstraints {
            int gridwidth = REMAINDER;

            Insets insets = {
                double top = 72.0/8;
            };
        },
    };

    Login() {
        components.$_failed.text = "";
        sleep(1.0);
        components.$_failed.text = "Login failed - try again";
    }

    ShowScreen() {
        Point point;

        if (!visible) {
            point.x = (VM.screen.width - size.width)/2;
            point.y = (VM.screen.height - size.height)/2 - 72.0;
            location = point;
            visible = TRUE;
        }
    }
};

screen.ShowScreen();
that builds and displays a simple login screen. Notice how we mixed the styles and also used the automatic substitution of JLabels for text strings. Once again we encourage you to experiment with this script. For example, try adding some padding, say 72.0, to the layout array responsible for the labels and textfields and see if you understand what happens. Notice that you can get horizontal or vertical spacing, depending on where you put the padding.

We also often use a GridBagLayout when we want to center buttons in a screen and put other components in the same row but anchor them to the left or right side of the screen. Wrapping an extra JPanel around the buttons in the last example gives us the script,

import yoix.*.*;

JDialog screen = {
    Dimension size = NULL;
    String    font = "Dialog-bold-12";
    double    border = 72.0/8;
    int       modal = TRUE;

    GridBagLayout layoutmanager;
    Array layout = {
        new JLabel {
            String text = "Example Login Screen";
            String font = "Dialog-bold-16";
            Color  foreground = Color.red;
        },
        new GridBagConstraints {
            int gridwidth = REMAINDER;
        },

        new JPanel {
            GridBagLayout layoutmanager = {
                int    columns = 2;
                double vgap = 72.0/32;
            };

            Array layout = {
                "Username",
                RIGHT,
                new JTextField {
                    String tag = "$_username";
                    int    columns = 10;
                    int    requestfocus = TRUE;

                    textValueChanged(e) {
                        root.components.$_failed.text = "";
                    }
                },
                LEFT,

                "Password",
                new JTextField {
                    String tag = "$_password";
                    int    columns = 10;
                    int    echo = '*';

                    textValueChanged(e) {
                        root.components.$_failed.text = "";
                    }
                },

                "Group",
                new JTextField {
                    String tag = "$_group";
                    int    columns = 10;

                    textValueChanged(e) {
                        root.components.$_failed.text = "";
                    }
                },
            };
        },
        new GridBagConstraints {
            int gridwidth = REMAINDER;
            int ipadx = 3.0*72;

            Insets insets = {
                double top = 72.0/4;
            };
        },

        new JLabel {
            String tag = "$_failed";
            Color  foreground = Color.red;
        },
        new GridBagConstraints {
            int gridwidth = REMAINDER;
            int weighty = 1;

            Insets insets = {
                double top = 72.0/4;
                double bottom = 72.0/4;
            };
        },

        new JPanel {
            GridBagLayout layoutmanager;
            Array layout = {
                new JPanel {
                    GridLayout layoutmanager;
                    Array layout = {
                        new JButton {
                            String text = "OK";

                            actionPerformed(e) {
                                root.Login();
                            }
                        },

                        new JButton {
                            String text = "Quit";
                            Color  foreground = Color.red;

                            actionPerformed(e) {
                                exit(0);
                            }
                        },
                    };
                },
                //
                // Set defaults so everything ends
                // up in the same cell.
                // 
                new Dictionary {
                    int gridx = 1;
                    int gridy = 1;
                    int weightx = 1;
                },

                new JChoice {
                    String selected = "two";

                    Array items = {
                        "First", "one",
                        "Second", "two",
                        "Three", "three",
                    };
                },
                RIGHT,
            };
        },
        new GridBagConstraints {
            int gridwidth = REMAINDER;
            int weightx = 1;
            int fill = HORIZONTAL;

            Insets insets = {
                double top = 72.0/8;
            };
        },
    };

    Login() {
        components.$_failed.text = "";
        sleep(1.0);
        components.$_failed.text = "Login failed - try again";
    }

    ShowScreen() {
        Point point;

        if (!visible) {
            point.x = (VM.screen.width - size.width)/2;
            point.y = (VM.screen.height - size.height)/2 - 72.0;
            location = point;
            visible = TRUE;
        }
    }
};

screen.ShowScreen();
and if you look carefully you will see that the technique that we used basically added the buttons and the choice to the same cell. The buttons are anchored to the center of the cell and the choice is anchored to the right side, so we get the layout behavior that we are looking for if the new JPanel horizontally fills the available space and the screen has a border that is horizontally symmetric.
 
 See Also:   BorderLayout, BoxLayout, CardLayout, CustomLayout, FlowLayout, GridLayout, LayoutManager

 

Yoix is a registered trademark of AT&T Inc.