Getting to Know BoxLayout

One of the standard layout managers that come with the Java platform is BoxLayout. This allows you to layout a single row or column of components in a container. This may sound like a not-so-complicated layout manager, but with the help of Box and its glue and struts, you'd think that would be enough, but there is even more. The vertical and horizontal alignment of the underlying components allows even more control of the positioning of components within the container. Here, we'll look at all these aspects.

Typical Usage

BoxLayout is unlike most layout managers which just require you to create the layout manager, and associate the layout manager with the Container. Instead, the BoxLayout constructor requires you to pass the Container into the constructor of the layout manager, thus having a reference to the other component in each of them. This can be awkward sometimes, and makes the use of the Box container more popular, since all you have to do is ask for a horizontally or vertically laid out Box through one of its static methods:

  Box vertical = Box.createVerticalBox();
  Box horizontal = Box.createHorizontalBox();

Both are using BoxLayout under the covers, placing added components on the proper access, depending upon direction. A vertical box places everything into a single column, whereas a horizontal box places everything in a row. Comparing BoxLayout (and thus Box) to GridLayout requires a quick comment. When placing a bunch of components in a GridLayout controlled container, all the components are expected to be the same size. With BoxLayout, that isn't the case, and the maximum preferred size of the component is honored.

Struts and Glue

The Box class offers the creation of two supporting components, one a strut, or fixed-size filler area, the other glue for an expandable area. The use of these allows you to place components within a container, either a fixed-distance apart with a strut, or a growing/shrinking area based upon available space, with glue. The same task can be done with GridBagConstraints and GridBagLayout, though not as easily.

To demonstrate, this first program creates a 25 pixel strut between the top two components and a 10 pixel strut between the bottom two.

import java.awt.\*;
import javax.swing.\*;
public class VerticalBoxTest {
  public static void main(String args[]) {
    JFrame frame = new JFrame("Vertical Box");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Box box = Box.createVerticalBox(); 
    box.add(new Button("Top"));
    box.add(Box.createVerticalStrut(25));
    box.add(new Button("Middle"));
    box.add(Box.createVerticalStrut(10));
    box.add(new Button("Bottom"));
    frame.add(box, BorderLayout.CENTER);
    frame.setSize(300, 200);
    frame.setVisible(true);
  }
}

Once you compile and run it, notice how the components change in size when the window size increased or decreased. The distance between the components remain unchanged, to match the reserved strut space. This example uses a <code>Button</code> instead of a JButton to avoid an explanation of component alignment until a little later.


Working with a horizontal box and glue produces similar results, though this time the glue grows in size to take up added space, instead of staying a fixed size, with the strut.

import java.awt.\*;
import javax.swing.\*;
public class HorizontalBoxTest {
  public static void main(String args[]) {
    JFrame frame = new JFrame("Horizontal Box");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Box box = Box.createHorizontalBox();
    box.add(Box.createHorizontalGlue());
    box.add(new JButton("Left"));
    box.add(new JButton("Right"));
    frame.add(box, BorderLayout.NORTH);
    box = Box.createHorizontalBox();
    box.add(new JButton("Left"));
    box.add(Box.createHorizontalGlue());
    box.add(new JButton("Right"));
    frame.add(box, BorderLayout.CENTER);
    box = Box.createHorizontalBox();
    box.add(new JButton("Left"));
    box.add(new JButton("Right"));
    box.add(Box.createHorizontalGlue());
    frame.add(box, BorderLayout.SOUTH);
    frame.setSize(300, 200);
    frame.setVisible(true);
  }
}


Trying not to confuse you too much, but the example is back to using JButton components.

Alignment

Life gets interesting with Box/BoxLayout when the components within the container are a different size or the height/width of the container is wider than necessary for a vertical box or taller than necessary with a horizontal one. In other words, if you have a tall column, where do components of a different width end up? And, if you have a wide row with components of a different height, how about them?

This is where the different alignments of a component come into play. Each Swing component has an X-alignment setting and a Y-alignment setting thanks to its get/setAlignmentX() and get/setAlignmentY() methods. The range of each setting is from 0 to 1.0, inclusive, where 0 represents left or top alignment and 1 represents right or bottom alignment, depending upon direction of BoxLayout. There are constants available in the Component class so you don't really need to know what the values are for right and left alignment. However, it does help to know if you might want something in between.

To demonstrate the right, left, center nature of different size buttons in a vertical box, the following program creates three boxes, one each filled with left, center, and right aligned buttons.

import java.awt.\*;
import javax.swing.\*;

public class AlignX {

  private static Container makeIt(String labelChar, float alignment) {
    Box box = Box.createVerticalBox();

    for (int i=1; i<6; i++) {
      String label = makeLabel(labelChar, i\*2);
      JButton button = new JButton(label);
      button.setAlignmentX(alignment);
      box.add(button);
    }
    return box;
  }

  private static String makeLabel(String s, int length) {
    StringBuffer buff = new StringBuffer(length);
    for (int i=0; i<length; i++) {
      buff.append(s);
    }
    return buff.toString();
  }

  public static void main(String args[]) {
    JFrame frame = new JFrame("X Alignment");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    Container panel1 = makeIt("L", Component.LEFT_ALIGNMENT);
    Container panel2 = makeIt("C", Component.CENTER_ALIGNMENT);
    Container panel3 = makeIt("R", Component.RIGHT_ALIGNMENT);

    frame.setLayout(new FlowLayout());
    frame.add(panel1);
    frame.add(panel2);
    frame.add(panel3);

    frame.pack();
    frame.setVisible(true);
  }
}

Now, let us mix things up a little and have one vertical box with three buttons, one for each alignment. The screen width will be wide, to make sure there is extra space available. Conceptually thinking, one would expect the component with left alignment to be aligned to the left of the container and the one with right alignment to be aligned to the right of the container. That would be wrong though. When there are different component alignments, they are aligned to the center of the container. So, for left alignment, that component will have its left edge on the invisible center line of the container. For right alignment, it is the right edge.

Here's the program to demonstrate:

import java.awt.\*;
import javax.swing.\*;

public class AlignX2 {

  public static void main(String args[]) {
    JFrame frame = new JFrame("X Alignment");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    Box box = Box.createVerticalBox();
    JButton button = new JButton("LL");
    button.setAlignmentX(Component.LEFT_ALIGNMENT);
    box.add(button);
    button = new JButton("CC");
    button.setAlignmentX(Component.CENTER_ALIGNMENT);
    box.add(button);
    button = new JButton("RR");
    button.setAlignmentX(Component.RIGHT_ALIGNMENT);
    box.add(button);
    frame.add(box, BorderLayout.CENTER);

    frame.setSize(300, 200);
    frame.setVisible(true);}
}

And, the corroborating screen:

Working in the other direction has top alignment aligning the top of the component to the imaginary center line, or in other words below the center.

Mixing up alignments in this fashion works fine, but just takes some getting used to, as the alignment isn't necessarily where you would expect it to be, unless all the alignments are the same, and then it does align to the container border, as opposed to the container center line.

If you are still confused, feel free to modify the earlier programs and try even more combinations of x and y alignment. Of course, if all this baffles you, there is always GridBagLayout.

\*\*\*\*\*\*

SDN Chat: Meet the Writers of java.sun.com
Please join us in Sun's Developer Playground in Second Life on Thursday, February 14 at 10am PST to meet the writers of java.sun.com. Ed Ort, Dana Nourie, Janice Heiss, and Laureen Hudson will be inworld to discuss their adventures in writing for one of the industry's most popular websites and to share the technologies and trends they'll be keeping their eyes on in 2008. And, for the first time, SMI Press is pleased to offer attendees one of three new SMI Press books for free!


Comments:

Post a Comment:
Comments are closed for this entry.
About

John O'Conner

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today