Skip to main content

Getting to know GroupLayout, part 2

Posted by tpavek on March 1, 2006 at 6:43 AM PST

Note: Since Java 6 release, an updated version of this text, including the code samples, is available as part of the Swing trail of Java Tutorial:
How to Use GroupLayout, GroupLayout example


The first part of this article provided the theory behind GroupLayout. Now it's time to try it on a real example.
So let's create a layout for this
dialog:

A good way to analyze the layout is to use a top-down decomposition. I'll
describe
the procedure that proved useful to me; step by step to make it clear. Once you get used to
"group thinking", you'll be able to proceed much
faster.

Horizontal layout

Examining the horizontal dimension from left to right, we
can see there are 3 groups in a sequence. The first one is actually not a group,
just a component -- the label. The second one is a group containing the text field and
the checkboxes (we'll decompose it later). And the third is a group of the two
buttons. As illustrated here:

Let's sketch out the sequential group in code. Note that
GroupLayout.LEADING corresponds to left alignment in the horizontal dimension. Also note we don't specify gaps, assuming the gap auto-insertion feature is turned on.

    layout.setHorizontalGroup(layout.createSequentialGroup()
        .add(label)
        .add(layout.createParallelGroup(GroupLayout.LEADING))
        .add(layout.createParallelGroup(GroupLayout.LEADING))
    );

Now let's decompose the group in the middle. This is the hardest one. There's a text field in
parallel with a sequence of two parallel groups each containing two checkboxes.
See the following illustration:

Let's add the corresponding code:

    layout.setHorizontalGroup(layout.createSequentialGroup()
        .add(label)

        .add(layout.createParallelGroup(GroupLayout.LEADING)
            .add(textField)
            .add(layout.createSequentialGroup()
                .add(layout.createParallelGroup(GroupLayout.LEADING)
                    .add(caseCheckBox)
                    .add(wholeCheckBox))
                .add(layout.createParallelGroup(GroupLayout.LEADING)
                    .add(wrapCheckBox)
                    .add(backCheckBox))))

        .add(layout.createParallelGroup(GroupLayout.LEADING))
    );

Note we want the text field to be resizable, but that happens automatically
since JTextField returns the right maximum size by default.

The remaining group on the right is trivial: it contains just two buttons. We even don't need the picture ;-) Here's the code:

    layout.setHorizontalGroup(layout.createSequentialGroup()
        .add(label)
        .add(layout.createParallelGroup(GroupLayout.LEADING)
            .add(textField)
            .add(layout.createSequentialGroup()
                .add(layout.createParallelGroup(GroupLayout.LEADING)
                    .add(caseCheckBox)
                    .add(wholeCheckBox))
                .add(layout.createParallelGroup(GroupLayout.LEADING)
                    .add(wrapCheckBox)
                    .add(backCheckBox))))

        .add(layout.createParallelGroup(GroupLayout.LEADING)
            .add(findButton)
            .add(cancelButton))

    );

And finally, we'd like the buttons to have always the same size, so let's link
them:

    layout.linkSize(new Component[] { findButton, cancelButton },
                    GroupLayout.HORIZONTAL);

Now we are done with the horizontal dimension. Let's switch to the vertical dimension. From now,
we'll only need to think about the y
axis.

Vertical layout

In the vertical dimension, we examine the layout from top to bottom. We
definitely want all the components on the first line aligned on baseline. So
along the vertical axis there is a sequence of the baseline group, followed by a
group of the remaining components. See the following picture.

Let's sketch out the code. First, we need to define two parallel groups. Note that
GroupLayout.LEADING corresponds to the top alignment in the
vertical dimension.

    layout.setVerticalGroup(layout.createSequentialGroup()
        .add(layout.createParallelGroup(GroupLayout.BASELINE))
        .add(layout.createParallelGroup(GroupLayout.LEADING))
    );

We can fill the baseline group right away:

    layout.setVerticalGroup(layout.createSequentialGroup()
        .add(layout.createParallelGroup(GroupLayout.BASELINE)
            .add(label)
            .add(textField)
            .add(findButton))

        .add(layout.createParallelGroup(GroupLayout.LEADING))
    );

Now let's look at the bottom group. Note the Cancel button is not on a shared
baseline with
the checkboxes; it is aligned at the top. So the second parallel group comprises
the button and a sequential group of two baseline groups with checkboxes:

The corresponding code looks as follows:

    layout.setVerticalGroup(layout.createSequentialGroup()
        .add(layout.createParallelGroup(GroupLayout.BASELINE)
            .add(label)
            .add(textField)
            .add(findButton))

        .add(layout.createParallelGroup(GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(layout.createParallelGroup(GroupLayout.BASELINE)
                    .add(caseCheckBox)
                    .add(wrapCheckBox))
                .add(layout.createParallelGroup(GroupLayout.BASELINE)
                    .add(wholeCheckBox)
                    .add(backCheckBox)))
            .add(cancelButton))

    );

So, that's it! We've created a
complete layout including resize behavior without specifying a single
number in pixels. That's a true cross platform layout! Note that we don't
need to specify gaps between components, we get correct spacing automatically
and according to the look and feel guidelines. Here's the complete code for
the Find dialog's layout:

    GroupLayout layout = new GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setAutocreateGaps(true);
    layout.setAutocreateContainerGaps(true);

    layout.setHorizontalGroup(layout.createSequentialGroup()
        .add(label)
        .add(layout.createParallelGroup(GroupLayout.LEADING)
            .add(textField)
            .add(layout.createSequentialGroup()
                .add(layout.createParallelGroup(GroupLayout.LEADING)
                    .add(caseCheckBox)
                    .add(wholeCheckBox))
                .add(layout.createParallelGroup(GroupLayout.LEADING)
                    .add(wrapCheckBox)
                    .add(backCheckBox))))
        .add(layout.createParallelGroup(GroupLayout.LEADING)
            .add(findButton)
            .add(cancelButton))
    );
    layout.linkSize(new Component[] { findButton, cancelButton },
                    GroupLayout.HORIZONTAL);

    layout.setVerticalGroup(layout.createSequentialGroup()
        .add(layout.createParallelGroup(GroupLayout.BASELINE)
            .add(label)
            .add(textField)
            .add(findButton))
        .add(layout.createParallelGroup(GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(layout.createParallelGroup(GroupLayout.BASELINE)
                    .add(caseCheckBox)
                    .add(wrapCheckBox))
                .add(layout.createParallelGroup(GroupLayout.BASELINE)
                    .add(wholeCheckBox)
                    .add(backCheckBox)))
            .add(cancelButton))
    );

Here is the complete Find.java file. You can compile
it and run against the Swing Layout Extensions library. Try resizing the dialog
horizontally to see how the layout automatically adjusts to the new size.

The easiest way to test GroupLayout is to use it with NetBeans 5.0
where it is bundled (just make sure "Swing Layout Extensions" library
is added in the libraries of the working project).

The layout manager and related extensions are hosted on http://swing-layout.dev.java.net
as one of the Swing Labs
projects (see the earlier Scott Violet's announcement).
You can get the latest version from the download
page
.


That's all for now. In future articles, I'll take a look at dynamic changes of the
layout, compare GroupLayout with other layout managers, describe its limitations,
and I'll cover other topics of interest based on your feedback.

Related Topics >>