Previous | Next | Trail Map | Creating a User Interface | Using the JFC/Swing Packages

How to Use BoxLayout

The Swing packages include a general purpose layout manager named BoxLayout(in the API reference documentation). BoxLayout either stacks its components on top of each other (with the first component at the top) or places them in a tight row from left to right -- your choice. You might think of it as a more full-featured version of FlowLayout(in the Creating a User Interface trail).

Note: This section assumes that you're familiar with layout managers. If you aren't, you can learn about them in the lesson Laying Out Components within a Container(in the Creating a User Interface trail).

By creating one or more lightweight containers that use BoxLayout, you can achieve layouts similar to those for which the more complex GridBagLayout(in the Creating a User Interface trail) is often used. BoxLayout is also useful in some situations where you might consider using GridLayout(in the Creating a User Interface trail) or BorderLayout(in the Creating a User Interface trail). One big difference between BoxLayout and the existing AWT layout managers is that BoxLayout respects the component's maximum size and X/Y alignment. We'll discuss that later.

The following figure shows a GUI that uses a BoxLayout to place components from left to right.

The following code lays out the GUI. This code is in the constructor for a container, which is implemented as a JPanel subclass. You can find the whole program in ImageChooser.java.

setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(scrollPane);
add(Box.createRigidArea(new Dimension(10, 0)));
add(pictureScrollPane);
setBorder(BorderFactory.createEmptyBorder(20,20,20,20));

The first line of the preceding code snippet creates a BoxLayout instance and makes it the layout manager for the container. The two arguments to the BoxLayout constructor are the container that it manages and the axis along with the components will be laid out. BoxLayout.X_AXIS specifies that the components are laid out from left to right. The other possible value is BoxLayout.Y_AXIS, which specifies top-to-bottom layout.

The next three lines of code add components to the container. The first and third components are scroll panes. The second component is a rigid area -- an invisible lightweight component used to add space between components. In this case, the rigid area has no height and puts exactly 10 pixels between the two scroll panes. Rigid areas are discussed later, in Using Invisible Components as Filler.

The last line of code adds a 20-pixel empty border around all four sides of the container. Borders are completely independent of layout managers. They're simply how Swing components draw their edges. See How to Use Borders for more information.

The following sections discuss BoxLayout in more detail:

Don't let the length of the BoxLayout discussion scare you! You can probably use BoxLayout with the information you already have. If you run into trouble or you want to take advantage of BoxLayout's power, read on.

Box Layout Features

As we said before, a BoxLayout arranges components either from top to bottom or from left to right. As it arranges components, the box layout takes the components' alignments and minimum, preferred, and maximum sizes into account. In this section, we'll talk about top-to-bottom (Y axis) layout. The same concepts apply to left-to-right layout. You simply substitute X for Y, height for width, and so on.

When a BoxLayout lays out components from top to bottom, it tries to size each component at the component's preferred height. If the amount of vertical space is not ideal, the box layout tries to adjust each components' height so that the components fill the available amount of space. However, the components might not fit exactly, since BoxLayout respects each component's requested minimum and maximum heights. Any extra space appears at the bottom of the container.

A top-to-bottom box layout tries to make all of its container's components equally wide -- as wide as the largest preferred width. If the container is forced to be wider than that, then the box layout tries to make all the components as wide as the container. If the components aren't all the same width (due to restricted maximum size or to any of them having strict left or right alignment), then X alignment comes into play.

The X alignments affect not only the components' positions relative to each other, but also the location of the components (as a group) within their container. The following figures illustrate alignment of components that have restricted maximum widths.

Three left-aligned components  Three center-aligned components  Three right-aligned components
In the first figure, all three components have an X alignment of 0.0 (Component.LEFT_ALIGNMENT). This means that the components' left sides should be aligned. Furthermore, it means that all three components are positioned as far left in their container as possible.

In the second figure, all three components have an X alignment of 0.5 (Component.CENTER_ALIGNMENT). This means that the components' centers should be aligned, and that the components should be positioned in the horizontal center of their container.

In the third figure, the components have an X alignment of 1.0 (Component.RIGHT_ALIGNMENT). You can guess what that means for the components' alignment and position relative to their container.

You might be wondering what happens when the components have both restricted maximum sizes and different X alignments. The next figure shows an example of this:

Three components with mixed X alignments
As you can see, the left side of the component with an X alignment of 0.0 (Component.LEFT_ALIGNMENT) is aligned with the center of the component that has the 0.5 X alignment (Component.CENTER_ALIGNMENT), which is aligned with the right side of the component that has an X alignment of 1.0 (Component.RIGHT_ALIGNMENT). Mixed alignments like this are further discussed in Fixing Alignment Problems.

What if none of the components has a maximum width? Well, if all the components have identical X alignment, then all components are made as wide as their container. If the X alignments are different, then any component with an X alignment of 0.0 (left) or 1.0 (right) will be smaller. All components with an intermediate X alignment (such as center) will be as wide as their container. Here are two examples:

Three components with mixed X alignments and no maximum size  Three components with mixed X alignments and no maximum size
To get to know BoxLayout better, you can run your own experiments with BoxLayoutDemo.

Try this:
  1. Compile and run BoxLayoutDemo. The source files are BoxLayoutDemo.java and Rectangle.java.
    See Getting Started with Swing if you need help. You'll see a window like the one above that contains three rectangles. Each rectangle is an instance of Rectangle, which is a JComponent subclass.
  2. Click inside one of the rectangles.
    This is how you change the rectangle's X alignment.
  3. Click the check box at the bottom of the window.
    This turns off restricted sizing for all the rectangles.
  4. Make the window taller.
    This makes the rectangles' container larger than the sum of the rectangles' preferred sizes. The container is a JPanel that has a red outline, so that you can tell where the container's edges are.

Using Invisible Components as Filler

Each component controlled by a box layout butts up against its neighboring components. If you want to have space between components, you can either add an empty border to one or both components, or insert invisible components to provide the space. You can create invisible components with the help of the Box class.

The Box(in the API reference documentation) class provides an inner class, Box.Filler(in the API reference documentation) that provides invisible components. The Box class provides convenience methods to help you create common kinds of filler. The following table gives details about creating invisible components with Box and Box.Filler.

[PENDING: Convert the figures in the following table and beyond from the magical world of ASCII to something presentable.]
Type Size Constraints How to Create
rigid area
  XXXXX
  XXXXX
  XXXXX
Box.createRigidArea(size)
glue horizontal
<- . ->
Box.createHorizontalGlue()
vertical
   ^
   |

   .

   |
   v
Box.createVerticalGlue()
custom Box.Filler (as specified)
new Box.Filler(minSize, prefSize, maxSize)

Here's how you generally use each type of filler:

Rigid area
Use this when you want a fixed-size space between two components. For example, to put 5 pixels between two components in a left-to-right box, you can use this code:
container.add(firstComponent);
container.add(Box.createRigidArea(new Dimension(5,0)));
container.add(secondComponent);

Without rigid area:        With rigid area:
-------------------        -------------------
|XXXXYYY          |        |XXXX     YYY     |
|XXXXYYY          |        |XXXX<--->YYY     |
|XXXXYYY          |        |XXXX     YYY     |
-------------------        -------------------


Note: The Box class provides another kind of filler for putting fixed space between components: a vertical or horizontal strut. Unfortunately, struts have unlimited maximum heights or widths (for horizontal and vertical struts, respectively). This means that if you use a horizontal box within a vertical box, for example, the horizontal box can sometimes become too tall. For this reason, we recommend that you use rigid areas instead of struts.

Glue
Use this to specify where excess space in a layout should go. Think of it as semi-wet glue -- stretchy and expandable, yet taking up no space unless you pull apart the components that it's sticking to. For example, by putting horizontal glue between two components in a left-to-right box, you make any extra space go between those components, instead of to the right of all the components. Here's an example of making the space in a left-to-right box go between two components, instead of to the right of the components:
container.add(firstComponent);
container.add(Box.createHorizontalGlue());
container.add(secondComponent);

Without glue:              With glue:
-------------------        -------------------
|XXXXYYY          |        |XXXX          YYY|
|XXXXYYY          |        |XXXX<-------->YYY|
|XXXXYYY          |        |XXXX          YYY|
-------------------        ------------------- 

Custom Box.Filler
Use this to specify a component with whatever minimum, preferred, and maximum sizes you want. For example, to create some filler in a left-to-right layout that puts at least 5 pixels between two components and ensures that the container has a minimum height of 100 pixels, you could use this code:
container.add(firstComponent);
Dimension minSize = new Dimension(5, 100);
Dimension prefSize = new Dimension(5, 100);
Dimension maxSize = new Dimension(Short.MAX_VALUE, 100);
container.add(new Box.Filler(minSize, prefSize, maxSize));
container.add(secondComponent);

Without filler:            With filler:
-------------------        -------------------
|XXXXYYY          |        |        ^        |
|XXXXYYY          |        |XXXX    |     YYY|
|XXXXYYY          |        |XXXX<-------->YYY|
-------------------        |XXXX    |     YYY|
                           |        v        |
                           ------------------- 

Fixing Alignment Problems

Two types of alignment problems sometimes occur with BoxLayout:

In general, all the components controlled by a top-to-bottom BoxLayout object should have the same X alignment. Similarly, all the components controlled by a left-to-right Boxlayout should generally have the same Y alignment. You can set a Swing component's X alignment by invoking its setAlignmentX method. An alternative is to override the getAlignmentX method in a custom subclass of the component class. Similarly, you set the Y alignment of a component by invoking the setAlignmentY method or by overriding getAlignmentY.

Here is an example, taken from AlignmentDemo.java, of changing the Y alignments of two buttons so that the buttons' bottoms are aligned:

button1.setAlignmentY(Component.BOTTOM_ALIGNMENT);
button2.setAlignmentY(Component.BOTTOM_ALIGNMENT);
As the following table shows, Swing buttons, labels, and menu items have a different default X alignment value from all other components. Similarly, buttons, menu items, and tool bars have a different Y alignment from all other components.

[PENDING: Is it a bug or a feature that Swing Component Default X Alignment Default Y Alignment Buttons, menu items LEFT_ALIGNMENT TOP_ALIGNMENT Labels LEFT_ALIGNMENT CENTER_ALIGNMENT Tool bars CENTER_ALIGNMENT TOP_ALIGNMENT All other Swing components CENTER_ALIGNMENT CENTER_ALIGNMENT

The AlignmentDemo.java program gives examples of fixing mismatched alignment problems. Usually, it's as simple as making the offending button or label be center aligned. For example:

label.setAlignmentX(Component.CENTER_ALIGNMENT);
...
button.setAlignmentY(Component.CENTER_ALIGNMENT);

Specifying Component Sizes

As we mentioned before, BoxLayout pays attention to a component's requested minimum, preferred, and maximum sizes. While you're fine tuning the layout, you might need to adjust these sizes.

Sometimes the need to adjust the size is obvious. For example, a Swing button's maximum size is the same as its preferred size. If you want the button to be drawn wider when additional space is available, then you obviously need to change its maximum size.

Sometimes, however, the need to adjust size is not so obvious. You might be getting unexpected results with a box layout, and you might not know why. In this case, it's usually best to treat the problem as an alignment problem first. If adjusting the alignments doesn't help, then you might have a size problem. We'll discuss this further a bit later.


Note: Although BoxLayout pays attention to a component's maximum size, most layout managers do not. For example, if you put a button in the SOUTH part of a BorderLayout, the button will probably be wider than its preferred width. BoxLayout, on the other hand, never makes a button wider than its preferred width unless you specifically change the button's maximum size.

You can change the minimum, preferred, and maximum sizes in two ways:

If you're running into trouble with a box layout and you've ruled out alignment problems, then the trouble might well be size-related. Here are some problems to check for:

Is the container controlled by the box layout taking up too much space?
If so, then one or more of the components in the container probably needs to have its maximum size restricted.
[PENDING: what else?]
You can use two techniques to track down size trouble in a box layout:

The Box Layout API

The following tables list the commonly used BoxLayout and Box constructors and methods. The API for using box layouts falls into these categories:

Creating BoxLayout Objects
Constructor or Method Purpose
BoxLayout(Container, int) Creates a BoxLayout instance that controls the specified Container. The integer argument specifies whether the container's components should be laid out left to right (BoxLayout.X_AXIS) or top to bottom (BoxLayout.Y_AXIS).
Box(int) Creates a Box -- a lightweight container that uses a BoxLayout with the specified alignment (BoxLayout.X_AXIS or BoxLayout.Y_AXIS). Note that a Box is not a JComponent -- it's implemented as a subclass of Container. This makes it as lightweight as possible, but it lacks JComponent features such as borders. If you want a simple JComponent as a container, use JPanel.
static Box createHorizontalBox() Creates a Box that lays out its components from left to right.
static Box createVerticalBox() Creates a Box that lays out its components from top to bottom.

Creating Space Fillers
Constructor or Method Purpose
Component createHorizontalGlue()
Component createVerticalGlue()
Component createGlue()
Create a glue lightweight component. Horizontal glue and vertical glue can be very useful.
Component createHorizontalStrut()
Component createVerticalStrut()
Create a "strut" lightweight component. We recommend using rigid areas instead of struts.
Box.Filler(Dimension, Dimension, Dimension) Creates a lightweight component with the specified minimum, preferred, and maximum sizes (with the arguments specified in that order). See the custom Box.Filler discussion, earlier in this section, for details.

Other Useful Methods
Method Purpose
void changeShape(Dimension, Dimension, Dimension) (in Box.Filler) Change the minimum, preferred, and maximum sizes of the recipient Box.Filler object. The layout changes accordingly.

Examples that Use BoxLayout

[PENDING: Put list of examples here. The current, unabridged list:


Previous | Next | Trail Map | Creating a User Interface | Using the JFC/Swing Packages