1.6 Laying Out Components Within a Container

«« Previous
Next »»

This lesson tells you how to use the layout managers provided by the Java platform. It also tells you how to use absolute positioning (no layout manager) and gives an example of writing a custom layout manager. For each layout manager (or lack thereof), this lesson points to an example that you can run using Java™ Web Start. By resizing an example's window, you can see how size changes affect the layout.

◉ A Visual Guide to Layout Managers


Several AWT and Swing classes provide layout managers for general use:

BorderLayout

Oracle Java Tutorials and Materials, Oracle Java Certifications

Every content pane is initialized to use a BorderLayout. (As Using Top-Level Containers explains, the content pane is the main container in all frames, applets, and dialogs.) A BorderLayout places components in up to five areas: top, bottom, left, right, and center. All extra space is placed in the center area. Tool bars that are created using JToolBar must be created within a BorderLayout container, if you want to be able to drag and drop the bars away from their starting positions.

BoxLayout


Oracle Java Tutorials and Materials, Oracle Java Certifications

The BoxLayout class puts components in a single row or column. It respects the components' requested maximum sizes and also lets you align components.

CardLayout

Oracle Java Tutorials and Materials, Oracle Java Certifications

The CardLayout class lets you implement an area that contains different components at different times. A CardLayout is often controlled by a combo box, with the state of the combo box determining which panel (group of components) the CardLayout displays. An alternative to using CardLayout is using a tabbed pane, which provides similar functionality but with a pre-defined GUI.

FlowLayout

Oracle Java Tutorials and Materials, Oracle Java Certifications

FlowLayout is the default layout manager for every JPanel. It simply lays out components in a single row, starting a new row if its container is not sufficiently wide.

GridBagLayout

Oracle Java Tutorials and Materials, Oracle Java Certifications

GridBagLayout is a sophisticated, flexible layout manager. It aligns components by placing them within a grid of cells, allowing components to span more than one cell. The rows in the grid can have different heights, and grid columns can have different widths.

GridLayout

Oracle Java Tutorials and Materials, Oracle Java Certifications

GridLayout simply makes a bunch of components equal in size and displays them in the requested number of rows and columns.

GroupLayout

Oracle Java Tutorials and Materials, Oracle Java Certifications

GroupLayout is a layout manager that was developed for use by GUI builder tools, but it can also be used manually. GroupLayout works with the horizontal and vertical layouts separately. The layout is defined for each dimension independently. Consequently, however, each component needs to be defined twice in the layout. The Find window shown above is an example of a GroupLayout.

SpringLayout

Oracle Java Tutorials and Materials, Oracle Java Certifications

Oracle Java Tutorials and Materials, Oracle Java Certifications

SpringLayout is a flexible layout manager designed for use by GUI builders. It lets you specify precise relationships between the edges of components under its control. For example, you might define that the left edge of one component is a certain distance (which can be dynamically calculated) from the right edge of a second component. SpringLayout lays out the children of its associated container according to a set of constraints, as shall be seen in How to Use SpringLayout.

This section shows example GUIs that use these layout managers, and tells you where to find the how-to page for each layout manager.

◉ Using Layout Managers

A layout manager is an object that implements the LayoutManager interface* and determines the size and position of the components within a container. Although components can provide size and alignment hints, a container's layout manager has the final say on the size and position of the components within the container.

Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.
If you are interested in using JavaFX to create your GUI

This section discusses some of the common tasks related to using layout managers:

Setting the Layout Manager

As a rule, the only containers whose layout managers you need to worry about are JPanels and content panes. Each JPanel object is initialized to use a FlowLayout, unless you specify differently when creating the JPanel. Content panes use BorderLayout by default. If you do not like the default layout manager that a panel or content pane uses, you are free to change it to a different one. However, unless you are using JToolBar, the FlowLayout and BorderLayout managers are only useful for prototyping. Any real application will need to reset the layout manager. Again, you should use an appropriate tool to do this, rather than coding the manager by hand.

You can set a panel's layout manager using the JPanel constructor. For example:

JPanel panel = new JPanel(new BorderLayout());

After a container has been created, you can set its layout manager using the setLayout method. For example:

Container contentPane = frame.getContentPane();
contentPane.setLayout(new FlowLayout());

Although we strongly recommend that you use layout managers, you can perform layout without them. By setting a container's layout property to null, you make the container use no layout manager. With this strategy, called absolute positioning, you must specify the size and position of every component within that container. One drawback of absolute positioning is that it does not adjust well when the top-level container is resized. It also does not adjust well to differences between users and systems, such as different font sizes and locales.

Adding Components to a Container

When you add components to a panel or content pane, the arguments you specify to the add method depend on the layout manager that the panel or content pane is using. In fact, some layout managers do not even require you to add the component explicitly; for example, GroupLayout. For example, BorderLayout requires that you specify the area to which the component should be added (using one of the constants defined in BorderLayout) using code like this:

pane.add(aComponent, BorderLayout.PAGE_START);

The how-to section for each layout manager has details on what, if any, arguments you need to specify to the add method. Some layout managers, such as GridBagLayout and SpringLayout, require elaborate setup procedures. Many layout managers, however, simply place components based on the order they were added to their container.

Swing containers other than JPanel and content panes generally provide API that you should use instead of the add method. For example, instead of adding a component directly to a scroll pane (or, actually, to its viewport), you either specify the component in the JScrollPane constructor or use setViewportView. Because of specialized API like this, you do not need to know which layout manager (if any) many Swing containers use. (For the curious: scroll panes happen to use a layout manager named ScrollPaneLayout.)

Providing Size and Alignment Hints

Sometimes you need to customize the size hints that a component provides to its container's layout manager, so that the component will be laid out well. You can do this by specifying one or more of the minimum, preferred, and maximum sizes of the component. You can invoke the component's methods for setting size hints — setMinimumSize, setPreferredSize, and setMaximumSize. Or you can create a subclass of the component that overrides the appropriate getter methods — getMinimumSize, getPreferredSize, and getMaximumSize. Here is an example of making a component's maximum size unlimited:

component.setMaximumSize(new Dimension(Integer.MAX_VALUE,
                                       Integer.MAX_VALUE));

Many layout managers do not pay attention to a component's requested maximum size. However, BoxLayout and SpringLayout do. Furthermore, GroupLayout provides the ability to set the minimum, preferred or maximum size explicitly, without touching the component.

Besides providing size hints, you can also provide alignment hints. For example, you can specify that the top edges of two components should be aligned. You set alignment hints either by invoking the component's setAlignmentX and setAlignmentY methods, or by overriding the component's getAlignmentX and getAlignmentY methods. Although most layout managers ignore alignment hints, BoxLayout honors them. You can find examples of setting the alignment in How to Use BoxLayout.

Putting Space Between Components

Three factors influence the amount of space between visible components in a container:

The layout manager
Some layout managers automatically put space between components; others do not. Some let you specify the amount of space between components. See the how-to page for each layout manager for information about spacing support.

Invisible components
You can create lightweight components that perform no painting, but that can take up space in the GUI. Often, you use invisible components in containers controlled by BoxLayout. See How to Use BoxLayout for examples of using invisible components.

Empty borders
No matter what the layout manager, you can affect the apparent amount of space between components by adding empty borders to components. The best candidates for empty borders are components that typically have no default border, such as panels and labels. Some other components might not work well with borders in some look-and-feel implementations, because of the way their painting code is implemented.

Setting the Container's Orientation

This website is written in English, with text that runs from left to right, and then top to bottom. However, many other languages have different orientations. The componentOrientation property provides a way of indicating that a particular component should use something different from the default left-to-right, top-to-bottom orientation. In a component such as a radio button, the orientation might be used as a hint that the look and feel should switch the locations of the icon and text in the button. In a container, the orientation is used as a hint to the layout manager.

To set a container's orientation, you can use either the Component-defined method setComponentOrientation or, to set the orientation on the container's children as well, applyComponentOrientation. The argument to either method can be a constant such as ComponentOrientation.RIGHT_TO_LEFT, or it can be a call to the ComponentOrientation method getOrientation(Locale). For example, the following code causes all JComponents to be initialized with an Arabic-language locale, and then sets the orientation of the content pane and all components inside it accordingly:

JComponent.setDefaultLocale(new Locale("ar"));
JFrame frame = new JFrame();
...
Container contentPane = frame.getContentPane();
contentPane.applyComponentOrientation(
    ComponentOrientation.getOrientation(
        contentPane.getLocale()));

Here are two pictures showing how FlowLayout lays out components in containers that are exactly the same, except for their orientation.

Oracle Java Tutorials and Materials, Oracle Java Certifications
Default orientation (left-to-right)

Oracle Java Tutorials and Materials, Oracle Java Certifications
Right-to-left orientation

he standard layout managers that support component orientation are FlowLayout, BorderLayout, BoxLayout, GridBagLayout, and GridLayout.

Note: Care must be taken that the component orientation is applied to renderers, editors and any other components unreachable through normal traversal of the containment hierarchy.

Tips on Choosing a Layout Manager

Layout managers have different strengths and weaknesses. This section discusses some common layout scenarios and which layout managers might work for each scenario. However, once again, it is strongly recommended that you use a builder tool to create your layout managers, such as the NetBeans IDE Matisse GUI builder, rather than coding managers by hand. The scenarios listed below are given for information purposes, in case you are curious about which type of manager is used in different situations, or in case you absolutely must code your manager manually.

If none of the layout managers we discuss is right for your situation and you cannot use a builder tool, feel free to use other layout managers that you may write or find. Also keep in mind that flexible layout managers such as GridBagLayout and SpringLayout can fulfill many layout needs.

Scenario: You need to display a component in as much space as it can get.
If it is the only component in its container, use GridLayout or BorderLayout. Otherwise, BorderLayout or GridBagLayout might be a good match.

If you use BorderLayout, you will need to put the space-hungry component in the center. With GridBagLayout, you will need to set the constraints for the component so that fill=GridBagConstraints.BOTH. Another possibility is to use BoxLayout, making the space-hungry component specify very large preferred and maximum sizes.

Scenario: You need to display a few components in a compact row at their natural size.
Consider using a JPanel to group the components and using either the JPanel's default FlowLayout manager or the BoxLayout manager. SpringLayout is also good for this.

Scenario: You need to display a few components of the same size in rows and columns.
GridLayout is perfect for this.

Scenario: You need to display a few components in a row or column, possibly with varying amounts of space between them, custom alignment, or custom component sizes.
BoxLayout is perfect for this.

Scenario: You need to display aligned columns, as in a form-like interface where a column of labels is used to describe text fields in an adjacent column.
SpringLayout is a natural choice for this. The SpringUtilities class used by several Tutorial examples defines a makeCompactGrid method that lets you easily align multiple rows and columns of components.

Scenario: You have a complex layout with many components.
Consider either using a very flexible layout manager such as GridBagLayout or SpringLayout, or grouping the components into one or more JPanels to simplify layout. If you take the latter approach, each JPanel might use a different layout manager.

Third-Party Layout Managers

Other third party layout managers have been created by the Swing community, to complement those provided by the Java platform. The following list is by no means definitive, but the layout managers listed below are the most popular:

1. MiGLayout
2. Karsten Lentzsch's FormLayout

◉ How Layout Management Works

If you are interested in using JavaFX to create your GUI.

Here is an example of a layout management sequence for a container using LayoutManager2.

1. Layout managers basically do two things:
  • Calculate the minimum/preferred/maximum sizes for a container.
  • Lay out the container's children.
Layout managers do this based on the provided constraints, the container's properties (such as insets) and on the children's minimum/preferred/maximum sizes. If a child is itself a container then its own layout manger is used to get its minimum/preferred/maximum sizes and to lay it out.

2. A container can be valid (namely, isValid() returns true) or invalid. For a container to be valid, all the container's children must be laid out already and must all be valid also. The Container.validate method can be used to validate an invalid container. This method triggers the layout for the container and all the child containers down the component hierarchy and marks this container as valid.

3. After a component is created it is in the invalid state by default. The Window.pack method validates the window and lays out the window's component hierarchy for the first time.

The end result is that to determine the best size for the container, the system determines the sizes of the containers at the bottom of the containment hierarchy. These sizes then percolate up the containment hierarchy, eventually determining the container's total size.

If the size of a component changes, for example following a change of font, the component must be resized and repainted by calling the revalidate and repaint methods on that component. Both revalidate and repaint are thread-safe — you need not invoke them from the event-dispatching thread.

When you invoke revalidate on a component, a request is passed up the containment hierarchy until it encounters a container, such as a scroll pane or top-level container, that should not be affected by the component's resizing. (This is determined by calling the container's isValidateRoot method.) The container is then laid out, which has the effect of adjusting the revalidated component's size and the size of all affected components.

◉ How to Use Various Layout Managers

Each of the following pages describes how to use a particular kind of layout manager. Another way to get to these pages is through A Visual Guide to Layout Managers.

Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.
If you are interested in using JavaFX to create your GUI, see Working With Layouts in JavaFX.

➥How to Use BorderLayout
➥How to Use BoxLayout
➥How to Use CardLayout
➥How to Use FlowLayout
➥How to Use GridBagLayout
➥How to Use GridLayout
➥How to Use GroupLayout
➥How to Use SpringLayout

◉ How to Use BorderLayout

Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.

If you are interested in using JavaFX to create your GUI.

The following figure represents a snapshot of an application that uses the BorderLayout class.

Oracle Java Tutorials and Materials, Oracle Java Certification

Click the Launch button to run BorderLayoutDemo using Java™ Web Start (download JDK 7 or later). Alternatively, to compile and run the example yourself, consult the example index.

The complete code of this demo is in the BorderLayoutDemo.java file.

As the preceding picture shows, a BorderLayout object has five areas. These areas are specified by the BorderLayout constants:
  • PAGE_START
  • PAGE_END
  • LINE_START
  • LINE_END
  • CENTER
Version note: 

Before JDK release 1.4, the preferred names for the various areas were different, ranging from points of the compass (for example, BorderLayout.NORTH for the top area) to wordier versions of the constants we use in our examples. The constants our examples use are preferred because they are standard and enable programs to adjust to languages that have different orientations.

If the window is enlarged, the center area gets as much of the available space as possible. The other areas expand only as much as necessary to fill all available space. Often a container uses only one or two of the areas of the BorderLayout object — just the center, or the center and the bottom.

The following code adds components to a frame's content pane. Because content panes use the BorderLayout class by default, the code does not need to set the layout manager. The complete program is in the BorderLayoutDemo.java file.

...//Container pane = aFrame.getContentPane()...
JButton button = new JButton("Button 1 (PAGE_START)");
pane.add(button, BorderLayout.PAGE_START);

//Make the center component big, since that's the
//typical usage of BorderLayout.
button = new JButton("Button 2 (CENTER)");
button.setPreferredSize(new Dimension(200, 100));
pane.add(button, BorderLayout.CENTER);

button = new JButton("Button 3 (LINE_START)");
pane.add(button, BorderLayout.LINE_START);

button = new JButton("Long-Named Button 4 (PAGE_END)");
pane.add(button, BorderLayout.PAGE_END);

button = new JButton("5 (LINE_END)");
pane.add(button, BorderLayout.LINE_END);

Specify the component's location (for example, BorderLayout.LINE_END) as one of the arguments to the add method. If this component is missing from a container controlled by a BorderLayout object, make sure that the component's location was specified and no another component was placed in the same location.

All tutorial examples that use the BorderLayout class specify the component as the first argument to the add method. For example:

add(component, BorderLayout.CENTER)  //preferred

However, the code in other programs specifies the component as the second argument. For example, here are alternate ways of writing the preceding code:

add(BorderLayout.CENTER, component)  //valid but old fashioned
    or
add("Center", component)             //valid but error prone

The BorderLayout API


The following table lists constructors and methods to specify gaps (in pixels).

Specifying gaps

Constructor or Method Purpose
BorderLayout(int horizontalGap, int verticalGap) Defines a border layout with specified gaps between components
setHgap(int) Sets the horizontal gap between components.
setVgap(int) Sets the vertical gap between components.

Examples that Use BorderLayout


The following table lists code examples that use the BorderLayout class and provides links to related sections.

Where Described Where Described Notes
BorderLayoutDemo This page Puts a component in each of the five possible locations.
TabbedPaneDemo How to Use Tabbed Panes One of many examples that puts a single component in the center of a content pane, so that the component is as large as possible.
CheckBoxDemo How to Use Check Boxes Creates a JPanel object that uses the BorderLayout class. Puts components into the left (actually, LINE_START) and center locations.


◉ How to Use BoxLayout

Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.
If you are interested in using JavaFX to create your GUI.

The Swing packages include a general purpose layout manager named BoxLayout. BoxLayout either stacks its components on top of each other or places them in a row — your choice. You might think of it as a version of FlowLayout, but with greater functionality. Here is a picture of an application that demonstrates using BoxLayout to display a centered column of components:

Oracle Java Tutorials and Materials, Oracle Java Certifications

Click the Launch button to run BoxLayoutDemo using Java™ Web Start (download JDK 7 or later). Alternatively, to compile and run the example yourself, consult the example index.

Launches the BoxLayoutDemo example
You can see the code in BoxLayoutDemo.java.

The following figure shows a GUI that uses two instances of BoxLayout. In the top part of the GUI, a top-to-bottom box layout places a label above a scroll pane. In the bottom part of the GUI, a left-to-right box layout places two buttons next to each other. A BorderLayout combines the two parts of the GUI and ensures that any excess space is given to the scroll pane.

Oracle Java Tutorials and Materials, Oracle Java Certifications

The following code, taken from ListDialog.java, lays out the GUI. This code is in the constructor for the dialog, which is implemented as a JDialog subclass. The bold lines of code set up the box layouts and add components to them.

JScrollPane listScroller = new JScrollPane(list);
listScroller.setPreferredSize(new Dimension(250, 80));
listScroller.setAlignmentX(LEFT_ALIGNMENT);
...
//Lay out the label and scroll pane from top to bottom.
JPanel listPane = new JPanel();
listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
JLabel label = new JLabel(labelText);
...
listPane.add(label);
listPane.add(Box.createRigidArea(new Dimension(0,5)));
listPane.add(listScroller);
listPane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));

//Lay out the buttons from left to right.
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
buttonPane.add(Box.createHorizontalGlue());
buttonPane.add(cancelButton);
buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
buttonPane.add(setButton);

//Put everything together, using the content pane's BorderLayout.
Container contentPane = getContentPane();
contentPane.add(listPane, BorderLayout.CENTER);
contentPane.add(buttonPane, BorderLayout.PAGE_END);

The first bold line creates a top-to-bottom box layout and sets it up as the layout manager for listPane. The two arguments to the BoxLayout constructor are the container that it manages and the axis along which the components will be laid out. The PAGE_AXIS constant specifies that components should be laid out in the direction that lines flow across a page as determined by the target container's ComponentOrientation property. The LINE_AXIS constant specifies that components should be laid out in the direction of a line of text as determined by the target container's ComponentOrientation property. These constants allow for internationalization, by laying out components in their container with the correct left-to-right, right-to-left or top-to-bottom orientation for the language being used.

The next three bold lines add the label and scroll pane to the container, separating them with a rigid area — an invisible component used to add space between components. In this case, the rigid area has no width and puts exactly 5 pixels between the label and scroll pane. Rigid areas are discussed later, in Using Invisible Components as Filler.

The next chunk of bold code creates a left-to-right box layout and sets it up for the buttonPane container. Then the code adds two buttons to the container, using a rigid area to put 10 pixels between the buttons. To place the buttons at the right side of their container, the first component added to the container is glue. This glue is an invisible component that grows as necessary to absorb any extra space in its container.

As an alternative to using invisible components, you can sometimes use empty borders to create space around components, most particularly panels. For example, the preceding code snippet uses empty borders to put 10 pixels between all sides of the dialog and its contents, and between the two parts of the contents. Borders are completely independent of layout managers. They are simply how Swing components draw their edges and provide padding between the content of the component and the edge.

The following sections discuss BoxLayout in more detail:
  • Box layout features
  • Using invisible components as filler
  • Fixing alignment problems
  • Specifying component sizes
  • The box layout API
  • Examples that use box layouts
Do not 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 said before, BoxLayout arranges components either on top of each other or in a row. As the box layout arranges components, it takes the components' alignments and minimum, preferred, and maximum sizes into account. In this section, we will talk about top-to-bottom layout. The same concepts apply to left-to-right or right-to-left layout. You simply substitute X for Y, height for width, and so on.

Version note: Before JDK version 1.4, no constants existed for specifying the box layout's axis in a localizable way. Instead, you specified X_AXIS (left to right) or Y_AXIS (top to bottom) when creating the BoxLayout. Our examples now use the constants LINE_AXIS and PAGE_AXIS, which are preferred because they enable programs to adjust to languages that have different orientations. In the default, left-to-right orientation, LINE_AXIS specifies left-to-right layout and PAGE_AXIS specifies top-to-bottom layout.

When a BoxLayout lays out components from top to bottom, it tries to size each component at the component's preferred height. If the vertical space of the layout does not match the sum of the preferred heights, then BoxLayout tries to resize the components to fill the space. The components either grow or shrink to fill the space, with BoxLayout honoring the minimum and maximum sizes of each of the components. Any extra space appears at the bottom of the container.

For a top-to-bottom box layout, the preferred width of the container is that of the maximum preferred width of the children. If the container is forced to be wider than that, BoxLayout attempts to size the width of each component to that of the container's width (minus insets). If the maximum size of a component is smaller than the width of the container, 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.

Oracle Java Tutorials and Materials, Oracle Java CertificationsOracle Java Tutorials and Materials, Oracle Java CertificationsOracle Java Tutorials and Materials, Oracle Java Certifications

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:

Oracle Java Tutorials and Materials, Oracle Java Certifications

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? In this case, 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:

Oracle Java Tutorials and Materials, Oracle Java CertificationsOracle Java Tutorials and Materials, Oracle Java Certifications

To get to know BoxLayout better, you can run your own experiments with BoxLayoutDemo2.

Try this: 

1. Click the Launch button to run BoxLayoutDemo2 using Java™ Web Start (download JDK 7 or later). Alternatively, to compile and run the example yourself, consult the example index.Launches the BoxLayoutDemo2 example

You can see the code in BoxLayoutDemo2.java.
You will see a window like the one above that contains three rectangles. Each rectangle is an instance of BLDComponent, 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 class defines a nested class, Box.Filler, that is a transparent component that paints nothing, and is used to provide space between other components. However, Filler is not actually invisible, because setVisible(false) is not invoked. 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.

Type Size Constraints How to Create
rigid area
Oracle Java Tutorials and Materials, Oracle Java Certifications, Oracle Java

Box.createRigidArea(size)
glue, horizontal
Oracle Java Tutorials and Materials, Oracle Java Certifications, Oracle Java
Box.createHorizontalGlue()
glue, vertical
Oracle Java Tutorials and Materials, Oracle Java Certifications, Oracle Java
Box.createVerticalGlue()
custom Box.Filler (as specified) new Box.Filler(minSize, prefSize, maxSize)

Here is 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);

Oracle Java Tutorials and Materials, Oracle Java Certifications, Oracle JavaOracle Java Tutorials and Materials, Oracle Java Certifications, Oracle Java

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 a kind of elastic glue — stretchy and expandable, yet taking up no space unless you pull apart the components that it is 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 is 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);

Oracle Java Tutorials and Materials, Oracle Java Certifications, Oracle JavaOracle Java Tutorials and Materials, Oracle Java Certifications, Oracle Java

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);

Oracle Java Tutorials and Materials, Oracle Java Certifications, Oracle JavaOracle Java Tutorials and Materials, Oracle Java Certifications, Oracle Java

Fixing Alignment Problems

Two types of alignment problems sometimes occur with BoxLayout:
  • A group of components all have the same alignment, but you want to change their alignment to make them look better. For example, instead of having the centers of a group of left-to-right buttons all in a line, you might want the bottoms of the buttons to be aligned. Here is an example:
Oracle Java Tutorials and Materials, Oracle Java Certifications, Oracle Java
  • Two or more components controlled by a BoxLayout have different default alignments, which causes them to be mis-aligned. For example, as the following shows, if a label and a panel are in a top-to-bottom box layout, the label's left edge is, by default, aligned with the center of the panel.
Oracle Java Tutorials and Materials, Oracle Java Certifications, Oracle Java

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 JComponent's X alignment by invoking its setAlignmentX method. An alternative available to all components 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 an application called BoxAlignmentDemo, of changing the Y alignments of two buttons so that the bottoms of the buttons are aligned:

button1.setAlignmentY(Component.BOTTOM_ALIGNMENT);
button2.setAlignmentY(Component.BOTTOM_ALIGNMENT);

Click the Launch button to run BoxAlignmentDemo using Java™ Web Start (download JDK 7 or later). Alternatively, to compile and run the example yourself, consult the example index.

By default, most components have center X and Y alignment. However, buttons, combo boxes, labels, and menu items have a different default X alignment value: LEFT_ALIGNMENT. The previous picture shows what happens if you put a left-aligned component such as a label together with a center-aligned component in a container controlled by a top-to-bottom BoxLayout.

The BoxAlignmentDemo program gives examples of fixing mismatched alignment problems. Usually, it is as simple as making an offending button or label be center aligned. For example:

label.setAlignmentX(Component.CENTER_ALIGNMENT);

Specifying Component Sizes

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

Sometimes the need to adjust the size is obvious. For example, a button's maximum size is generally the same as its preferred size. If you want the button to be drawn wider when additional space is available, then you 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 is usually best to treat the problem as an alignment problem first. If adjusting the alignments does not 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, many layout managers do not. For example, if you put a button in the bottom part of a BorderLayout, the button will probably be wider than its preferred width, no matter what the button's maximum size is. BoxLayout, on the other hand, never makes a button wider than its maximum size.
You can change the minimum, preferred, and maximum sizes in two ways:
  • By invoking the appropriate setXxxSize method (which is defined by the JComponent class). For example:
comp.setMinimumSize(new Dimension(50, 25));
comp.setPreferredSize(new Dimension(50, 25));
comp.setMaximumSize(new Dimension(Short.MAX_VALUE,
                                  Short.MAX_VALUE));
  • By overriding the appropriate getXxxSize method. For example:
...//in a subclass of a component class:
public Dimension getMaximumSize() {
    size = getPreferredSize();
    size.width = Short.MAX_VALUE;
    return size;
}

If you are running into trouble with a box layout and you have ruled out alignment problems, then the trouble might well be size-related. For example, if the container controlled by the box layout is taking up too much space, then one or more of the components in the container probably needs to have its maximum size restricted.

You can use two techniques to track down size trouble in a box layout:
  • Add a garish line border to the outside of the Swing components in question. This lets you see what size they really are. For example:
comp.setBorder(BorderFactory.createCompoundBorder(
                   BorderFactory.createLineBorder(Color.red),
                   comp.getBorder()));
  • Use System.out.println to print the components' minimum, preferred, and maximum sizes, and perhaps their bounds.
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 the axis along which the container's components should be laid out. When the container has the default component orientation, BoxLayout.LINE_AXIS specifies that the components be laid out from left to right, and BoxLayout.PAGE_AXIS specifies that the components be laid out from top to bottom.
Box(int) Creates a Box — a container that uses a BoxLayout with the specified axis.
static Box createHorizontalBox()
(in Box)
Creates a Box that lays out its components from left to right.
static Box createVerticalBox()
(in Box)
Creates a Box that lays out its components from top to bottom.

Creating Space Fillers
These methods are defined in the Box class.
Constructor or Method Purpose
Component createRigidArea(Dimension) Create a rigid component.
Component createHorizontalGlue()
Component createVerticalGlue()
Component createGlue()
Create a glue component. Horizontal glue and vertical glue can be very useful.
Component createHorizontalStrut()
Component createVerticalStrut()
Create a "strut" component. We recommend using rigid areas instead of struts.
Box.Filler(Dimension, Dimension, Dimension) Creates a 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
MethodPurpose
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 Box Layouts

The following table lists some of the many examples that use box layouts.

Example Where Described- Notes
BoxLayoutDemo2 This page-Uses a box layout to create a centered column of components.
BoxAlignmentDemo This page-Demonstrates how to fix common alignment problems.
BoxLayoutDemo This page-Lets you play with alignments and maximum sizes.
ListDialog This page- A simple yet realistic example of using both a top-to-bottom box layout and a left-to-right one. Uses horizontal glue, rigid areas, and empty borders. Also sets the X alignment of a component.
InternalFrameEventDemo How to Write an Internal Frame Listener-Uses a top-to-bottom layout to center buttons and a scroll pane in an internal frame.
MenuGlueDemo Customizing Menu Layout-Shows how to right-align a menu in the menu bar, using a glue component.
MenuLayoutDemo Customizing Menu Layout-Shows how to customize menu layout by changing the menu bar to use a top-to-bottom box layout, and the popup menu to use a left-to-right box layout.
ConversionPanel.java in the Converter demo How to Use Panels-Aligns two components in different box-layout-controlled containers by setting the components' widths to be the same, and their containers' widths to be the same.

◉ How to Use CardLayout


Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.

If you are interested in using JavaFX to create your GUI.

The following figure represents a snapshot of an application that uses the CardLayout class to switch between two panels.

Java Tutorials and Materials, Java Certifications, Java Guides

Java Tutorials and Materials, Java Certifications, Java Guides

Click the Launch button to run CardLayoutDemo using Java™ Web Start (download Java SE). Alternatively, to compile and run the example yourself, consult the example index.

The complete code of this demo is in the CardLayoutDemo.java file.

The CardLayout class manages two or more components (usually JPanel instances) that share the same display space. When using the CardLayout class, let the user choose between the components by using a combo box. The CardLayoutDemo application is an example to illustrate this feature.

Another way to accomplish the same task is to use a tabbed pane. The following picture shows a tabbed pane version of the preceding example:

Java Tutorials and Materials, Java Certifications, Java Guides

Because a tabbed pane provides its own GUI, using a tabbed pane is simpler than using the CardLayout class. For example, implementing the preceding example using a tabbed pane results in a program with fewer lines of code.

Click the Launch button to run TabDemo using Java™ Web Start (download JDK 7 or later). Alternatively, to compile and run the example yourself, consult the example index.

The complete code of this demo is in the TabDemo.java file.

Conceptually, each component that a CardLayout manages is like a playing card or trading card in a stack, where only the top card is visible at any time. You can choose the card that is showing in any of the following ways:
  • By asking for either the first or last card, in the order it was added to the container
  • By flipping through the deck backwards or forwards
  • By specifying a card with a specific name
The CardLayoutDemo class uses the last scheme.

The following code snippet from the CardLayoutDemo.java application creates the CardLayout object and the components it manages.

//Where instance variables are declared:
JPanel cards;
final static String BUTTONPANEL = "Card with JButtons";
final static String TEXTPANEL = "Card with JTextField";

//Where the components controlled by the CardLayout are initialized:
//Create the "cards".
JPanel card1 = new JPanel();
...
JPanel card2 = new JPanel();
...

//Create the panel that contains the "cards".
cards = new JPanel(new CardLayout());
cards.add(card1, BUTTONPANEL);
cards.add(card2, TEXTPANEL);

To add a component to a container that a CardLayout object manages, specify a string that identifies the component being added. For example, in this demo, the first panel has the string "Card with JButtons", and the second panel has the string "Card with JTextField". In this demo those strings are also used in the combo box.

To choose which component a CardLayout object shows, put additional code in your code example:

//Where the GUI is assembled:
//Put the JComboBox in a JPanel to get a nicer look.
JPanel comboBoxPane = new JPanel(); //use FlowLayout
String comboBoxItems[] = { BUTTONPANEL, TEXTPANEL };
JComboBox cb = new JComboBox(comboBoxItems);
cb.setEditable(false);
cb.addItemListener(this);
comboBoxPane.add(cb);
...
pane.add(comboBoxPane, BorderLayout.PAGE_START);
pane.add(cards, BorderLayout.CENTER);
...

//Method came from the ItemListener class implementation,
//contains functionality to process the combo box item selecting
public void itemStateChanged(ItemEvent evt) {
    CardLayout cl = (CardLayout)(cards.getLayout());
    cl.show(cards, (String)evt.getItem());
}

This example shows that to use the show method of the CardLayout class, you must set the currently visible component. The first argument in the show method is the container the CardLayout controls — that is, the container of the components the CardLayout manages. The second argument is the string that identifies the component to show. This string is the same string that was used when adding the component to the container.

The CardLayout API


The following table lists the CardLayout class methods that are used to choose a component. For each method, the first argument is the container for which the CardLayout is the layout manager (the container of the cards the CardLayout controls).

Method Purpose
first (Container parent) Flips to the first card of the container.
next (Container parent) Flips to the next card of the container. If the currently visible card is the last one, this method flips to the first card in the layout.
previous (Container parent) Flips to the previous card of the container. If the currently visible card is the first one, this method flips to the last card in the layout.
last (Container parent) Flips to the last card of the container.
show (Container parent, String name) Flips to the component that was added to this layout with the specified name, using the addLayoutComponent method.

Examples that Use CardLayout


Only one example in this trail uses CardLayout, and this is the CardLayoutDemo. Generally, our examples use tabbed panes instead of CardLayout, since a tabbed pane provides its own GUI.

◉ How to Use FlowLayout

Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.
If you are interested in using JavaFX to create your GUI.

The FlowLayout class provides a very simple layout manager that is used, by default, by the JPanel objects. The following figure represents a snapshot of an application that uses the flow layout:

Oracle Java Tutorials, SAP Certifications

Click the Launch button to run FlowLayoutDemo using Java™ Web Start (download JDK 7 or later). Alternatively, to compile and run the example yourself, consult the example index.

The complete code of this demo is in the FlowLayoutDemo.java file.

The FlowLayout class puts components in a row, sized at their preferred size. If the horizontal space in the container is too small to put all the components in one row, the FlowLayout class uses multiple rows. If the container is wider than necessary for a row of components, the row is, by default, centered horizontally within the container. To specify that the row is to aligned either to the left or right, use a FlowLayout constructor that takes an alignment argument. Another constructor of the FlowLayout class specifies how much vertical or horizontal padding is put around the components.

The code snippet below creates a FlowLayout object and the components it manages.

FlowLayout experimentLayout = new FlowLayout();

...

    compsToExperiment.setLayout(experimentLayout);

    compsToExperiment.add(new JButton("Button 1"));
    compsToExperiment.add(new JButton("Button 2"));
    compsToExperiment.add(new JButton("Button 3"));
    compsToExperiment.add(new JButton("Long-Named Button 4"));
    compsToExperiment.add(new JButton("5"));

Select either the Left to Right or Right to Left option and click the Apply orientation button to set up the component's orientation. The following code snippet applies the Left to Right components orientation to the experimentLayout.

        compsToExperiment.setComponentOrientation(
                ComponentOrientation.LEFT_TO_RIGHT);

The FlowLayout API

The following table lists constructors of the FlowLayout class.

Constructor Purpose
FlowLayout() Constructs a new FlowLayout object with a centered alignment and horizontal and vertical gaps with the default size of 5 pixels.
FlowLayout(int align) Creates a new flow layout manager with the indicated alignment and horizontal and vertical gaps with the default size of 5 pixels. The alignment argument can be FlowLayout.LEADING, FlowLayout.CENTER, or FlowLayout.TRAILING. When the FlowLayout object controls a container with a left-to right component orientation (the default), the LEADING value specifies the components to be left-aligned and the TRAILING value specifies the components to be right-aligned.
FlowLayout (int align, int hgap, int vgap) Creates a new flow layout manager with the indicated alignment and the indicated horizontal and vertical gaps. The hgap and vgap arguments specify the number of pixels to put between components.

Examples that Use FlowLayout

The following table lists code examples that use the FlowLayout class and provides links to related sections.

Example Where Described Notes
FlowLayoutDemo This page Sets up a content pane to use FlowLayout. If you set the RIGHT_TO_LEFT constant to true and recompile, you can see how FlowLayout handles a container that has a right-to-left component orientation.
CardLayoutDemo How to Use CardLayout Centers a component nicely in the top part of a BorderLayout, and puts the component in a JPanel that uses a FlowLayout.
ButtonDemo How to Use Buttons, Check Boxes, and Radio Buttons Uses the default FlowLayout of a JPanel.
TextInputDemo How to Use Formatted Text Fields Uses a panel with a right-aligned FlowLayout presenting two buttons.

◉ How to Use GridBagLayout

Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.


If you are interested in using JavaFX to create your GUI.

Here is a picture of an example that uses GridBagLayout.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Click the Launch button to run GridBagLayoutDemo using Java™ Web Start (download JDK 7 or later). Alternatively, to compile and run the example yourself, consult the example index.

The code for GridBagDemo is in GridBagLayoutDemo.java.

package layout;

/*
 * GridBagLayoutDemo.java requires no other files.
 */

import java.awt.*;
import javax.swing.JButton;
import javax.swing.JFrame;

public class GridBagLayoutDemo {
    final static boolean shouldFill = true;
    final static boolean shouldWeightX = true;
    final static boolean RIGHT_TO_LEFT = false;

    public static void addComponentsToPane(Container pane) {
        if (RIGHT_TO_LEFT) {
            pane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
        }

        JButton button;
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
if (shouldFill) {
//natural height, maximum width
c.fill = GridBagConstraints.HORIZONTAL;
}

button = new JButton("Button 1");
if (shouldWeightX) {
c.weightx = 0.5;
}
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
pane.add(button, c);

button = new JButton("Button 2");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 1;
c.gridy = 0;
pane.add(button, c);

button = new JButton("Button 3");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 0;
pane.add(button, c);

button = new JButton("Long-Named Button 4");
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 40;      //make this component tall
c.weightx = 0.0;
c.gridwidth = 3;
c.gridx = 0;
c.gridy = 1;
pane.add(button, c);

button = new JButton("5");
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 0;       //reset to default
c.weighty = 1.0;   //request any extra vertical space
c.anchor = GridBagConstraints.PAGE_END; //bottom of space
c.insets = new Insets(10,0,0,0);  //top padding
c.gridx = 1;       //aligned with button 2
c.gridwidth = 2;   //2 columns wide
c.gridy = 2;       //third row
pane.add(button, c);
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("GridBagLayoutDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Set up the content pane.
        addComponentsToPane(frame.getContentPane());

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

GridBagLayout is one of the most flexible — and complex — layout managers the Java platform provides. A GridBagLayout places components in a grid of rows and columns, allowing specified components to span multiple rows or columns. Not all rows necessarily have the same height. Similarly, not all columns necessarily have the same width. Essentially, GridBagLayout places components in rectangles (cells) in a grid, and then uses the components' preferred sizes to determine how big the cells should be.

The following figure shows the grid for the preceding applet. As you can see, the grid has three rows and three columns. The button in the second row spans all the columns; the button in the third row spans the two right columns.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

If you enlarge the window as shown in the following figure, you will notice that the bottom row, which contains Button 5, gets all the new vertical space. The new horizontal space is split evenly among all the columns. This resizing behavior is based on weights the program assigns to individual components in the GridBagLayout. You will also notice that each component takes up all the available horizontal space — but not (as you can see with button 5) all the available vertical space. This behavior is also specified by the program.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

The way the program specifies the size and position characteristics of its components is by specifying constraints for each component. The preferred approach to set constraints on a component is to use the Container.add variant, passing it a GridBagConstraints object, as demonstrated in the next sections.

The following sections explain the constraints you can set and provide examples.

Specifying Constraints

The following code is typical of what goes in a container that uses a GridBagLayout. You will see a more detailed example in the next section.

JPanel pane = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();

//For each component to be added to this container:
//...Create the component...
//...Set instance variables in the GridBagConstraints instance...
pane.add(theComponent, c);

As you might have guessed from the above example, it is possible to reuse the same GridBagConstraints instance for multiple components, even if the components have different constraints. However, it is recommended that you do not reuse GridBagConstraints, as this can very easily lead to you introducing subtle bugs if you forget to reset the fields for each new instance.

Note: The following discussion assumes that the GridBagLayout controls a container that has a left-to-right component orientation.

You can set the following GridBagConstraints instance variables:

gridx, gridy

Specify the row and column at the upper left of the component. The leftmost column has address gridx=0 and the top row has address gridy=0. Use GridBagConstraints.RELATIVE (the default value) to specify that the component be placed just to the right of (for gridx) or just below (for gridy) the component that was added to the container just before this component was added. We recommend specifying the gridx and gridy values for each component rather than just using GridBagConstraints.RELATIVE; this tends to result in more predictable layouts.

gridwidth, gridheight

Specify the number of columns (for gridwidth) or rows (for gridheight) in the component's display area. These constraints specify the number of cells the component uses, not the number of pixels it uses. The default value is 1. Use GridBagConstraints.REMAINDER to specify that the component be the last one in its row (for gridwidth) or column (for gridheight). Use GridBagConstraints.RELATIVE to specify that the component be the next to last one in its row (for gridwidth) or column (for gridheight). We recommend specifying the gridwidth and gridheight values for each component rather than just using GridBagConstraints.RELATIVE and GridBagConstraints.REMAINDER; this tends to result in more predictable layouts.

Note: GridBagLayout does not allow components to span multiple rows unless the component is in the leftmost column or you have specified positive gridx and gridy values for the component.

fill

Used when the component's display area is larger than the component's requested size to determine whether and how to resize the component. Valid values (defined as GridBagConstraints constants) include NONE (the default), HORIZONTAL (make the component wide enough to fill its display area horizontally, but do not change its height), VERTICAL (make the component tall enough to fill its display area vertically, but do not change its width), and BOTH (make the component fill its display area entirely).

ipadx, ipady

Specifies the internal padding: how much to add to the size of the component. The default value is zero. The width of the component will be at least its minimum width plus ipadx*2 pixels, since the padding applies to both sides of the component. Similarly, the height of the component will be at least its minimum height plus ipady*2 pixels.

insets

Specifies the external padding of the component -- the minimum amount of space between the component and the edges of its display area. The value is specified as an Insets object. By default, each component has no external padding.

anchor

Used when the component is smaller than its display area to determine where (within the area) to place the component. Valid values (defined as GridBagConstraints constants) are CENTER (the default), PAGE_START, PAGE_END, LINE_START, LINE_END, FIRST_LINE_START, FIRST_LINE_END, LAST_LINE_END, and LAST_LINE_START.

Here is a picture of how these values are interpreted in a container that has the default, left-to-right component orientation.

FIRST_LINE_START PAGE_START FIRST_LINE_END
LINE_START CENTER LINE_END
LAST_LINE_START PAGE_END LAST_LINE_END

Version note: The PAGE_* and *LINE_* constants were introduced in 1.4. Previous releases require values named after points of the compass. For example, NORTHEAST indicates the top-right part of the display area. We recommend that you use the new constants, instead, since they enable easier localization.

weightx, weighty

Specifying weights is an art that can have a significant impact on the appearance of the components a GridBagLayout controls. Weights are used to determine how to distribute space among columns (weightx) and among rows (weighty); this is important for specifying resizing behavior.
Unless you specify at least one non-zero value for weightx or weighty, all the components clump together in the center of their container. This is because when the weight is 0.0 (the default), the GridBagLayout puts any extra space between its grid of cells and the edges of the container.

Generally weights are specified with 0.0 and 1.0 as the extremes: the numbers in between are used as necessary. Larger numbers indicate that the component's row or column should get more space. For each column, the weight is related to the highest weightx specified for a component within that column, with each multicolumn component's weight being split somehow between the columns the component is in. Similarly, each row's weight is related to the highest weighty specified for a component within that row. Extra space tends to go toward the rightmost column and bottom row.

The next section discusses constraints in depth, in the context of explaining how the example program works.

The Example Explained

Here, again, is a picture of the GridBagLayoutDemo application.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Click the Launch button to run GridBagLayoutDemo using Java™ Web Start (download JDK 7 or later). Alternatively, to compile and run the example yourself, consult the example index.

The following code creates the GridBagLayout and the components it manages. You can find the entire source file in GridBagLayoutDemo.java.

JButton button;
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
if (shouldFill) {
                //natural height, maximum width
                c.fill = GridBagConstraints.HORIZONTAL;
}

button = new JButton("Button 1");
if (shouldWeightX) {
                   c.weightx = 0.5;
}
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
pane.add(button, c);

button = new JButton("Button 2");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 1;
c.gridy = 0;
pane.add(button, c);

button = new JButton("Button 3");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 0;
pane.add(button, c);

button = new JButton("Long-Named Button 4");
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 40;      //make this component tall
c.weightx = 0.0;
c.gridwidth = 3;
c.gridx = 0;
c.gridy = 1;
pane.add(button, c);

button = new JButton("5");
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 0;       //reset to default
c.weighty = 1.0;   //request any extra vertical space
c.anchor = GridBagConstraints.PAGE_END; //bottom of space
c.insets = new Insets(10,0,0,0);  //top padding
c.gridx = 1;       //aligned with button 2
c.gridwidth = 2;   //2 columns wide
c.gridy = 2;       //third row
pane.add(button, c);

This example uses one GridBagConstraints instance for all the components the GridBagLayout manages, however in real-life situations it is recommended that you do not reuse GridBagConstraints, as this can very easily lead to you introducing subtle bugs if you forget to reset the fields for each new instance. Just before each component is added to the container, the code sets (or resets to default values) the appropriate instance variables in the GridBagConstraints object. It then adds the component to its container, specifying the GridBagConstraints object as the second argument to the add method.

For example, to make button 4 be extra tall, the example has this code:

c.ipady = 40;

And before setting the constraints of the next component, the code resets the value of ipady to the default:

c.ipady = 0;

If a component's display area is larger than the component itself, then you can specify whereabouts in the display area the component will be displayed by using the GridBagConstraints.anchor constraint. The anchor constraint's values can be absolute (north, south, east, west, and so on), or orientation-relative (at start of page, at end of line, at the start of the first line, and so on), or relative to the component's baseline. For a full list of the possible values of the anchor constraint, including baseline-relative values,see the API documentation for GridBagConstraints.anchor. You can see in the code extract above that Button 5 specifies that it should be displayed at the end of the display area by setting an anchor at GridBagConstraints.PAGE_END.

Note: The Tutorial's examples used to specify the constraints object a different way, which you might see in other programs as well. Rather than specifying the constraints with the add method, our examples used to invoke the setConstraints method on the GridBagLayout object. For example:

GridBagLayout gridbag = new GridBagLayout();
pane.setLayout(gridbag);
...
gridbag.setConstraints(button, c);
pane.add(button);

However, we recommend you use the Container.add method since it makes for cleaner code than if you were to use setConstraints.

Here is a table that shows all the constraints for each component in GridBagLayoutDemo's content pane. Values that are not the default are marked in boldface. Values that are different from those in the previous table entry are marked in italics.

Component Constraints
All components ipadx = 0
fill = GridBagConstraints.HORIZONTAL
Button 1 ipady = 0 weightx = 0.5 weighty = 0.0 gridwidth = 1 anchor = GridBagConstraints.CENTER insets = new Insets(0,0,0,0) gridx = 0 gridy = 0
Button 2 weightx = 0.5
gridx = 1
gridy = 0
Button 3 weightx = 0.5
gridx = 2
gridy = 0
Button 4 ipady = 40
weightx = 0.0
gridwidth = 3
gridx = 0
gridy = 1
Button 5 ipady = 0
weightx = 0.0
weighty = 1.0
anchor = GridBagConstraints.PAGE_END
insets = new Insets(10,0,0,0)
gridwidth = 2
gridx = 1
gridy = 2

GridBagLayoutDemo has two components that span multiple columns (buttons 4 and 5). To make button 4 tall, we added internal padding (ipady) to it. To put space between buttons 4 and 5, we used insets to add a minimum of 10 pixels above button 5, and we made button 5 hug the bottom edge of its cell.

All the components in the pane container are as wide as possible, given the cells that they occupy. The program accomplishes this by setting the GridBagConstraints fill instance variable to GridBagConstraints.HORIZONTAL, leaving it at that setting for all the components. If the program did not specify the fill, the buttons would be at their natural width, like this:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

When you enlarge GridBagLayoutDemo's window, the columns grow proportionately. This is because each component in the first row, where each component is one column wide, has weightx = 0.5. The actual value of these components' weightx is unimportant. What matters is that all the components, and consequently, all the columns, have an equal weight that is greater than 0. If no component managed by the GridBagLayout had weightx set, then when the components' container was made wider, the components would stay clumped together in the center of the container, like this:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

If the container is given a size that is smaller or bigger than the prefered size, then any space is distributed according to the GridBagContainer weights.

Note that if you enlarge the window, the last row is the only one that gets taller. This is because only button 5 has weighty greater than zero.

The GridBagLayout API

The GridBagLayout and GridBagConstraints classes each have only one constructor, with no arguments. Instead of invoking methods on a GridBagConstraints object, you manipulate its instance variables, as described in Specifying Constraints. Generally, the only method you invoke on a GridBagLayout object is setConstraints, as demonstrated in The Example Explained.

Examples that Use GridBagLayout

You can find examples of using GridBagLayout throughout this tutorial. The following table lists a few.

Example Where Described Notes
GridBagLayoutDemo This section Uses many features — weights, insets, internal padding, horizontal fill, exact cell positioning, multi-column cells, and anchoring (component positioning within a cell).
TextSamplerDemo  Using Text Components Aligns two pairs of labels and text fields, plus adds a label across the full width of the container.
ContainerEventDemo How to Write a Container Listener Positions five components within a container, using weights, fill, and relative positioning.

◉ How to Use GridLayout

Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.

If you are interested in using JavaFX to create your GUI.

The following figure represents a snapshot of an application that uses the GridLayout class.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Click the Launch button to run GridLayoutDemo using Java™ Web Start (download JDK 7 or later). Alternatively, to compile and run the example yourself, consult the example index.

The complete code of this demo is in the GridLayoutDemo.java file.

A GridLayout object places components in a grid of cells. Each component takes all the available space within its cell, and each cell is exactly the same size. If the GridLayoutDemo window is resized, the GridLayout object changes the cell size so that the cells are as large as possible, given the space available to the container.

The code snippet below creates the GridLayout object and the components it manages.


GridLayout experimentLayout = new GridLayout(0,2);

...

        compsToExperiment.setLayout(experimentLayout);

        compsToExperiment.add(new JButton("Button 1"));
        compsToExperiment.add(new JButton("Button 2"));
        compsToExperiment.add(new JButton("Button 3"));
        compsToExperiment.add(new JButton("Long-Named Button 4"));
        compsToExperiment.add(new JButton("5"));

The constructor of the GridLayout class creates an instance that has two columns and as many rows as necessary.

Use combo boxes to set up how much vertical or horizontal padding is put around the components. Then click the Apply gaps button. The following code snippet shows how your selection is processed by using the setVgap and setHgap methods of the GridLayout class:


applyButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                //Get the horizontal gap value
                String horGap = (String)horGapComboBox.getSelectedItem();
                //Get the vertical gap value
                String verGap = (String)verGapComboBox.getSelectedItem();
                //Set up the horizontal gap value
                experimentLayout.setHgap(Integer.parseInt(horGap));
                //Set up the vertical gap value
                experimentLayout.setVgap(Integer.parseInt(verGap));
                //Set up the layout of the buttons
                experimentLayout.layoutContainer(compsToExperiment);
            }
        });

The GridLayout API

The following table lists constructors of the GridLayout class that specify the number of rows and columns.

The GridLayout class constructors

Constructor Purpose
GridLayout(int rows, int cols) Creates a grid layout with the specified number of rows and columns. All components in the layout are given equal size. One, but not both, of rows and cols can be zero, which means that any number of objects can be placed in a row or in a column.
GridLayout(int rows, int cols, int hgap, int vgap) Creates a grid layout with the specified number of rows and columns. In addition, the horizontal and vertical gaps are set to the specified values. Horizontal gaps are places between each of columns. Vertical gaps are placed between each of the rows.

The GridLayout class has two constructors:

Examples that Use GridLayout

The following table lists code examples that use the GridLayout class and provides links to related sections.

Example Where Described Notes
GridLayoutDemo This page Uses a 2-column grid.
ComboBoxDemo2 How to Use Combo Boxes One of many examples that use a 1x1 grid to make a component as large as possible.
LabelDemo How to Use Labels Uses a 3-row grid.

◉ How to Use GroupLayout

GroupLayout is a layout manager that was developed for GUI builders such as Matisse, the GUI builder provided with the NetBeans IDE. Although the layout manager was originally designed to suit the GUI builder needs, it also works well for manual coding. This discussion will teach you how GroupLayout works and show you how you can use GroupLayout to build GUIs, whether you choose to use a GUI builder like Matisse or write your own code.

Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.
If you are interested in using JavaFX to create your GUI, see Working With Layouts in JavaFX.

Design Principle: Independent Dimensions

GroupLayout works with the horizontal and vertical layouts separately. The layout is defined for each dimension independently. You do not need to worry about the vertical dimension when defining the horizontal layout, and vice versa, as the layout along each axis is totally independent of the layout along the other axis.

When focusing on just one dimension, you only have to solve half the problem at one time. This is easier than handling both dimensions at once. This means, of course, that each component needs to be defined twice in the layout. If you forget to do this, GroupLayout will generate an exception.

Layout Organization: Hierarchical Groups

GroupLayout uses two types of arrangements -- sequential and parallel, combined with hierarchical composition.

1. With sequential arrangement, the components are simply placed one after another, just like BoxLayout or FlowLayout would do along one axis. The position of each component is defined as being relative to the preceding component.

2. The second way places the components in parallel—on top of each other in the same space. They can be baseline-, top-, or bottom-aligned along the vertical axis. Along the horizontal axis, they can be left-, right-, or center-aligned if the components are not all the same size.

Usually, components placed in parallel in one dimension are in a sequence in the other, so that they do not overlap.

What makes these two arrangements powerful is that they can be nested hierarchically. For this purpose GroupLayout defines layout groups. A group is either sequential or parallel and may contain components, other groups, and gaps (discussed below).

The size of a sequential group is the sum of the sizes of the contained elements, and the size of a parallel group corresponds to the size of the largest element (although, depending on the elements and where the baseline lands, the size of a baseline-aligned group may be a bit larger than the largest element).

Defining a layout means defining how the components should be grouped by combining the sequential and parallel arrangements.

Let us use a simple example to see how it works in practice.

An Example

Let us start with something simple, just three components in a row:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

We will express this layout using groups. Starting with the horizontal axis it is easy to see there is a sequential group of 3 components arranged from left to right. Along the vertical axis there is a parallel group of the same 3 components with the same location, size, and baseline:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

In pseudo code, the layout specification might look like this (the real code is in the Writing Code section below):

horizontal layout = sequential group { c1, c2, c3 }
vertical layout = parallel group (BASELINE) { c1, c2, c3 }

This illustrates a principle mentioned earlier: components grouped sequentially in one dimension usually form a parallel group in the other dimension.

Now let us add one more component, C4, left-aligned with C3:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Along the horizontal axis the new component occupies the same horizontal space as C3 so that it forms a parallel group with C3. Along the vertical axis C4 forms a sequential group with the original parallel group of the three components.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

In pseudo code, the layout specification now looks like this:

horizontal layout = sequential group { c1, c2, parallel group (LEFT) { c3, c4 } }
vertical layout = sequential group { parallel group (BASELINE) { c1, c2, c3 }, c4 }
Now you understand the most important aspects of designing layouts with GroupLayout. There are just a few more details to explain: how to add gaps, how to define size and resize behavior, how to define justified layout, and how to write real code.

Gaps

A gap can be thought of as an invisible component of a certain size. Gaps of arbitrary size can be added to groups just like components or other groups. Using gaps you can precisely control the distance between components or from the container border.

GroupLayout also defines automatic gaps that correspond to preferred distances between neighboring components (or between a component and container border). The size of such a gap is computed dynamically based on the look and feel the application is using (the LayoutStyle class is used for this). There are two advantages to using automatic (preferred) gaps: you do not have to specify the pixel sizes of the gaps, and they automatically adjust to the look and feel the UI runs with, reflecting the actual look and feel guidelines.

GroupLayout distinguishes between (a) the preferred gap between two components and (b) the preferred gap between a component and the container border. There are corresponding methods in the GroupLayout API for adding these gaps (addPreferredGap and addContainerGap). There are three types of component gaps: related, unrelated and indented. The LayoutStyle.ComponentPlacement enum defines corresponding constants to be used as parameters of the addPreferredGap method: RELATED, UNRELATED and INDENT. The difference between related and unrelated gaps is just in size—the distance between unrelated components is a bit bigger. Indented represents a preferred horizontal distance of two components when one of them is positioned underneath the second with an indent.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

As mentioned above, GroupLayout can insert gaps automatically—if you do not add your own gaps explicitly, it adds the related preferred gaps for you. This is not the default behavior, however. You have to turn this feature on by invoking setAutoCreateGaps(true) and setAutoCreateContainerGaps(true) on the GroupLayout. Then you will get correct spacing automatically.

Writing Code

Now, let us take a look at the actual code to create the layout described above.

Let us assume we have a container named panel and the same four components already presented (c1, c2, c3, and c4). First, we create a new GroupLayout object and associate it with the panel:

GroupLayout layout = new GroupLayout(panel);
 panel.setLayout(layout);
We specify automatic gap insertion:

layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
Then, we define the groups and add the components. We establish a root group for each dimension using the setHorizontalGroup and setVerticalGroup methods. Groups are created via createSequentialGroup and createParallelGroup methods. Components are added to groups by using the addComponent method.

layout.setHorizontalGroup(
   layout.createSequentialGroup()
      .addComponent(c1)
      .addComponent(c2)
      .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
           .addComponent(c3)
           .addComponent(c4))
);
layout.setVerticalGroup(
   layout.createSequentialGroup()
      .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
           .addComponent(c1)
           .addComponent(c2)
           .addComponent(c3))
      .addComponent(c4)
);

You can specify the alignment for parallel groups. It can be one of the following constants defined in the GroupLayout.Alignment enum: LEADING, TRAILING, CENTER, and BASELINE. These constants are used for both dimensions and depend on whether the component orientation is left-to-right or right-to-left (top-to-bottom or bottom-to-top). For example, if the horizontal (vertical) component orientation is left-to-right (top-to-bottom) LEADING means left (top) while TRAILING means right (bottom). CENTER means "centered" in both dimensions. If you do not specify the alignment, LEADING will be used. The BASELINE alignment is valid only in the vertical dimension.

Note: Alignment in the layout of a group only has meaning for components of different sizes. Components of the same size will be automatically aligned for each of the GroupLayout.Alignment constants.

Some comments about the code:

◉ You do not need to add the component directly to the container—that is done for you implicitly when using one of the addComponent methods.
◉ Note the chained calls of the addComponent methods used to fill the groups. The addComponent method always returns the group on which it is called. Thanks to this you do not need to use local variables to hold the groups.
◉ It is a good idea to indent the code so it is easy to see the hierarchical structure of the groups. Give each component a new line, add one level of indent for each new group in the hierarchy. A good source editor will help you with pairing the parenthesis to close the createXXXGroup methods. By following these simple rules, it is easier to add a new component or remove an existing one.

Component Size and Resizability

There is no limit on the number of resizable components in a layout.

The size of each component in a GroupLayout is constrained by three values; minimum size, preferred size and maximum size. These sizes control how the component resizes within the layout. The GroupLayout.addComponent(...) method allows the size constraints to be specified.

If not specified explicitly, the layout asks the component for its default sizes (by using the component's getMinimumSize(), getPreferredSize() and getMaximumSize() methods). You do not need to specify anything for most of the components, like making JTextField resizable or JButton fixed, because the components themselves have the desired resizing behavior as default. On the other hand you can override the default behavior. For example you can make a JTextField fixed or JButton resizable.

GroupLayout defines constants that provide precise control over resize behavior. They can be used as parameters in the addComponent(Component comp, int min, int pref, int max)  method. Here are two examples:

1. To force a component to be resizable (allow shrinking and growing):

group.addComponent(component, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ...

This allows the component to resize between zero size (minimum) to any size (Short.MAX_VALUE as maximum size means "infinite"). If we wanted the component not to shrink below its default minimum size, we would use GroupLayout.DEFAULT_SIZE instead of 0 in the second parameter.

2. To make a component fixed size (suppress resizing):

group.addComponent(component, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE,
          GroupLayout.PREFERRED_SIZE) ...

In these examples the initial size of the component is not altered, its default size is the component's preferred size. If we wanted a specific size for the component, we would specify it in the second parameter instead of using GroupLayout.DEFAULT_SIZE.

Resizable gaps

Specifying size and resizability applies to gaps as well, including the preferred ones. For example, you can specify a preferred gap between two components that acts like a spring pushing the components away from each other (to the opposite sides of the container). The preferred distance of the two components is only used as the minimum size of the gap. See the following snippet:

layout.createSequentialGroup()
    .addComponent(c1)
    .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED,
                     GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
    .addComponent(c2);

Sizing in Parallel Groups

Resizable elements placed in a parallel group are stretched to fill the space of the group determined by the largest element in the group, so they end up aligned with the same size. GroupLayout also provides control over whether the enclosing parallel group itself should resize. If group resizing is suppressed, it prevents the contained elements from growing over the preferred size of the group. This way you can make a block of components align on both sides, or constrain individual components to have the same size.

Let us try to achieve the same size for two components from our example (c3 and c4 in the horizontal dimension):

layout.createParallelGroup(GroupLayout.Alignment.LEADING, false)
  .addComponent(c3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
  .addComponent(c4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE);
The underlying mechanism works as follows:

1. The size of the parallel group is set to the preferred size of the largest element; so to the preferred size of c4 in our example.

2. Resizable elements are stretched to the size of the group. In our example, only c3 is effectively stretched, the size of c4 already corresponds to the size of the group.

As a result, c3 and c4 would have the same width. The components would not resize further because the parallel group itself is not resizable (the second parameter of the createParallelGroup method, above, is false).

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Question for attentive readers: Why do we define both components in the parallel group as resizable in this example? It seems enough to have just c3 resizable since c4 is not stretched anyway...

The answer is: because of platform and localization independence. Otherwise we would have to rely on that c4 component always being bigger than c3. But this may change when the application runs on different platform or is translated to another language. By having both components resizeable they adjust to each other, no matter which one is bigger at a given moment.

Making Components the Same Size

The previous case is special because the components are in the same parallel group. But what if we wanted unrelated components to have the same size? Clearly, the same size cannot always be ensured by grouping. The OK and Cancel buttons in a row at the bottom of a dialog are a good example. For this purpose GroupLayout provides a linkSize method. This method allows the size of arbitrary components to be linked regardless of where they are placed. The resulting size of the linked components is set according to the largest component. For example:

layout.linkSize(SwingConstants.HORIZONTAL, c3, c4);
In this example, the size is linked selectively for the horizontal dimension.

Runtime Changes to Your GUI

There are two important methods that you can use to make changes to your GUI at runtime, replace() and setHonorsVisibility(). Using these two methods, you can exchange components or change the visibility of components at runtime and have the GUI rearrange itself accordingly.

replace(Component existingComponent, Component newComponent) replaces an existing component with a new one. One of the common operations needed for dynamic layouts is the ability to replace components like this. For example, perhaps a check box toggles between a component displaying a graph or a tree. GroupLayout makes this scenario simple with the replace() method. You can swap components without recreating all the groups.

Another common operation in user interfaces is to dynamically change the visibility of components. Perhaps components are shown only as a user completes earlier portions of a form. To avoid components shuffling around in such a scenario, space should be taken up regardless of the visibility of the components. GroupLayout offers two ways to configure how invisible components are treated. The setHonorsVisibility(boolean) method globally sets how invisible components are handled. A value of true, the default, indicates invisible components are treated as if they are not there. On the other hand, a value of false provides space for invisible components, treating them as though they were visible. The setHonorsVisibility(Component,Boolean) method can be used to configure the behavior at the level of a specific component. To determine how visibility is handled, GroupLayout first checks if a value has been specified for the Component, if not, it checks the setting of the global property.

Some history: 
GroupLayout in the Java Standard Edition 6 consists of three distinct bodies of work: the ability to get the baseline for a component, the ability to get the preferred gap between components (LayoutStyle), and GroupLayout. This work was originally done as an open source project at http://java.net/projects/swing-layout/

NetBeans 5.0 supports GroupLayout by way of the swing-layout project. Because of the success of this work, all three portions have been rolled into GroupLayout in Java Standard Edition version 6. The main difference between the GroupLayout in Java SE 6 and swing-layout is in the package name and method names. NetBeans 5.5 provides the ability to target either the GroupLayout in Java SE 6, or the GroupLayout in swing-layout. Which version NetBeans targets is determined by the version of the Java platform your project targets. A project targeting Java SE 6 uses the GroupLayout in Java SE, otherwise GroupLayout in swing-layout is used.

◉ A GroupLayout Example

Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.

If you are interested in using JavaFX to create your GUI.

As an example of GUI creation with GroupLayout, let us create a layout for this "Find" dialog box:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

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 check boxes (we will decompose it later). And the third is a group of the two buttons. As illustrated here:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

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

layout.setHorizontalGroup(layout.createSequentialGroup()
    .addComponent(label)
    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING))
    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING))
);

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

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Let us add the corresponding code:

layout.setHorizontalGroup(layout.createSequentialGroup()
    .addComponent(label)
    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
         .addComponent(textField)
         .addGroup(layout.createSequentialGroup()
              .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                  .addComponent(caseCheckBox)
                  .addComponent(wholeCheckBox))
              .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                  .addComponent(wrapCheckBox)
                  .addComponent(backCheckBox))))
     .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING))
);

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. Here is the code:

layout.setHorizontalGroup(layout.createSequentialGroup()
    .addComponent(label)
    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addComponent(textField)
        .addGroup(layout.createSequentialGroup()
            .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(caseCheckBox)
                .addComponent(wholeCheckBox))
            .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(wrapCheckBox)
                .addComponent(backCheckBox))))
    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addComponent(findButton)
        .addComponent(cancelButton))
);

And finally, we would like the buttons to be always the same size, so let us link them:

layout.linkSize(SwingConstants.HORIZONTAL, findButton, cancelButton);
Now we are done with the horizontal dimension. Let us switch to the vertical dimension. From now, we will 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 the 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.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

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

layout.setVerticalGroup(layout.createSequentialGroup()
    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE))
    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING))
);

We can fill the baseline group right away:

layout.setVerticalGroup(layout.createSequentialGroup()
    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
        .addComponent(label)
        .addComponent(textField)
        .addComponent(findButton))
    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING))
);

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

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

The corresponding code looks as follows:

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

So, we have created a complete layout, including resize behavior, without specifying a single number in pixels—a true cross platform layout. Note that we do not need to specify gaps between components, we get correct spacing automatically and according to the look and feel guidelines. Here is 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()
    .addComponent(label)
    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addComponent(textField)
        .addGroup(layout.createSequentialGroup()
            .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(caseCheckBox)
                .addComponent(wholeCheckBox))
            .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(wrapCheckBox)
                .addComponent(backCheckBox))))
    .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addComponent(findButton)
        .addComponent(cancelButton))
);

layout.linkSize(SwingConstants.HORIZONTAL, findButton, cancelButton);

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

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

package layout;

import java.awt.Component;
import javax.swing.*;
import static javax.swing.GroupLayout.Alignment.*;

public class Find extends JFrame {
    public Find() {
        JLabel label = new JLabel("Find What:");;
        JTextField textField = new JTextField();
        JCheckBox caseCheckBox = new JCheckBox("Match Case");
        JCheckBox wrapCheckBox = new JCheckBox("Wrap Around");
        JCheckBox wholeCheckBox = new JCheckBox("Whole Words");
        JCheckBox backCheckBox = new JCheckBox("Search Backwards");
        JButton findButton = new JButton("Find");
        JButton cancelButton = new JButton("Cancel");

        // remove redundant default border of check boxes - they would hinder
        // correct spacing and aligning (maybe not needed on some look and feels)
        caseCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
        wrapCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
        wholeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
        backCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));

        GroupLayout layout = new GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setAutoCreateGaps(true);
        layout.setAutoCreateContainerGaps(true);

        layout.setHorizontalGroup(layout.createSequentialGroup()
            .addComponent(label)
            .addGroup(layout.createParallelGroup(LEADING)
                .addComponent(textField)
                .addGroup(layout.createSequentialGroup()
                    .addGroup(layout.createParallelGroup(LEADING)
                        .addComponent(caseCheckBox)
                        .addComponent(wholeCheckBox))
                    .addGroup(layout.createParallelGroup(LEADING)
                        .addComponent(wrapCheckBox)
                        .addComponent(backCheckBox))))
            .addGroup(layout.createParallelGroup(LEADING)
                .addComponent(findButton)
                .addComponent(cancelButton))
        );
       
        layout.linkSize(SwingConstants.HORIZONTAL, findButton, cancelButton);

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

        setTitle("Find");
        pack();
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
    
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    UIManager.setLookAndFeel(
                                  "javax.swing.plaf.metal.MetalLookAndFeel");
                                //  "com.sun.java.swing.plaf.motif.MotifLookAndFeel");
                                //UIManager.getCrossPlatformLookAndFeelClassName());
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                new Find().setVisible(true);
            }
        });
    }
}

◉ How to Use SpringLayout


Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.

If you are interested in using JavaFX to create your GUI.

The SpringLayout class was added in JDK version 1.4 to support layout in GUI builders. SpringLayout is a very flexible layout manager that can emulate many of the features of other layout managers. SpringLayout is, however, very low-level and as such you really should only use it with a GUI builder, rather than attempting to code a spring layout manager by hand.

This section begins with a simple example showing all the things you need to remember to create your first spring layout — and what happens when you forget them! Later it presents utility methods that let you lay out components in a couple of different types of grids.

Here are pictures of some of the layouts we will cover:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

How Spring Layouts Work

Spring layouts do their job by defining directional relationships, or constraints, between the edges of components. For example, you might define that the left edge of one component is a fixed distance (5 pixels, say) from the right edge of another component.

In a SpringLayout, the position of each edge is dependent on the position of just one other edge. If a constraint is subsequently added to create a new binding for an edge, the previous binding is discarded and the edge remains dependent on a single edge.

Unlike many layout managers, SpringLayout does not automatically set the location of the components it manages. If you hand-code a GUI that uses SpringLayout, remember to initialize component locations by constraining the west/east and north/south locations. Depending on the constraints you use, you may also need to set the size of the container explicitly.

Components define edge properties, which are connected by Spring instances. Each spring has four properties — its minimum, preferred, and maximum values, and its actual (current) value. The springs associated with each component are collected into a SpringLayout.Constraints object.

An instance of the Spring class holds three properties that characterize its behavior: the minimum, preferred, and maximum values. Each of these properties may be involved in defining its fourth, value, property based on a series of rules.

An instance of the Spring class can be visualized as a mechanical spring that provides a corrective force as the spring is compressed or stretched away from its preferred value. This force is modelled as linear function of the distance from the preferred value, but with two different constants -- one for the compressional force and one for the tensional one. Those constants are specified by the minimum and maximum values of the spring such that a spring at its minimum value produces an equal and opposite force to that which is created when it is at its maximum value. The difference between the preferred and minimum values, therefore, represents the ease with which the spring can be compressed. The difference between its maximum and preferred values indicates the ease with which the Spring can be extended.

Based on this, a SpringLayout can be visualized as a set of objects that are connected by a set of springs on their edges.

Example: SpringDemo

This section takes you through the typical steps of specifying the constraints for a container that uses SpringLayout. The first example, SpringDemo1.java, is an extremely simple application that features a label and a text field in a content pane controlled by a spring layout. Here is the relevant code:

public class SpringDemo1 {
    public static void main(String[] args) {
        ...
        Container contentPane = frame.getContentPane();
        SpringLayout layout = new SpringLayout();
        contentPane.setLayout(layout);
        contentPane.add(new JLabel("Label: "));
        contentPane.add(new JTextField("Text field", 15));
        ...
        frame.pack();
        frame.setVisible(true);
    }
}

Click the Launch button to run SpringDemo1 using Java™ Web Start (download JDK 7 or later).

Here is what the GUI looks like when it first comes up:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Here is what it looks like when it is resized to be bigger:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Obviously, we have some problems. Not only does the frame come up way too small, but even when it is resized the components are all located at (0,0). This happens because we have set no springs specifying the components' positions and the width of the container. One small consolation is that at least the components are at their preferred sizes — we get that for free from the default springs created by SpringLayout for each component.

Our next example, SpringDemo2.java, improves the situation a bit by specifying locations for each component.Click the Launch button to run SpringDemo2 using Java™ Web Start (download JDK 7 or later).

Launches the SpringDemo2 example

In this example, we will specify that the components should appear in a single row, with 5 pixels between them. The following code specifies the location of the label:

//Adjust constraints for the label so it's at (5,5).
layout.putConstraint(SpringLayout.WEST, label,
                     5,
                     SpringLayout.WEST, contentPane);
layout.putConstraint(SpringLayout.NORTH, label,
                     5,
                     SpringLayout.NORTH, contentPane);

The first putConstraint call specifies that the label's left (west) edge should be 5 pixels from its container's left edge. This translates to an x coordinate of 5. The second putConstraint call sets up a similar relationship between the top (north) edges of the label and its container, resulting in a y coordinate of 5.

Here is the code that sets up the location of the text field:

//Adjust constraints for the text field so it's at
//(<label's right edge> + 5, 5).
layout.putConstraint(SpringLayout.WEST, textField,
                     5,
                     SpringLayout.EAST, label);
layout.putConstraint(SpringLayout.NORTH, textField,
                     5,
                     SpringLayout.NORTH, contentPane);

The first putConstraint call makes the text field's left (west) edge be 5 pixels away from the label's right (east) edge. The second putConstraint call is just like the second call in the first snippet, and has the same effect of setting the component's y coordinate to 5.

The previous example still has the problem of the container coming up too small. But when we resize the window, the components are in the right place:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

To make the container initially appear at the right size, we need to set the springs that define the right (east) and bottom (south) edges of the container itself. No constraints for the right and bottom container edges are set by default. The size of the container is defined by setting these constraints. SpringDemo3.java shows how to do this. Click the Launch button to run SpringDemo3 using Java™ Web Start (download JDK 7 or later). 

Here is the code that sets the container's springs:

layout.putConstraint(SpringLayout.EAST, contentPane,
                     5,
                     SpringLayout.EAST, textField);
layout.putConstraint(SpringLayout.SOUTH, contentPane,
                     5,
                     SpringLayout.SOUTH, textField);

The first putConstraint call makes the container's right edge be 5 pixels to the right of the text field's right edge. The second one makes its bottom edge be 5 pixels beyond the bottom edge of the tallest component (which, for simplicity's sake, we've assumed is the text field).

Finally, the window comes up at the right size:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

When we make the window larger we can see the spring layout in action, distributing the extra space between the available components.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

In this case the spring layout has chosen to give all the extra space to the text field. Although it seems like the spring layout treats labels and text fields differently, spring layout has no special knowledge of any Swing or AWT components. It relies on the values of a component's minimum, preferred, and maximum size properties. The next section discusses how spring layout uses these properties, and why they can cause uneven space distribution.

Springs and Component Size

A SpringLayout object automatically installs Springs for the height and width of each component that the SpringLayout controls. These springs are essentially covers for the component's getMinimumSize, getPreferredSize, and getMaximumSize methods. By "covers" we mean that not only are the springs initialized with the appropriate values from these methods, but also that the springs track those values. For example, the Spring object that represents the width of a component is a special kind of spring that simply delegates its implementation to the relevant size methods of the component. That way the spring stays in sync with the size methods as the characteristics of the component change.

When a component's getMaximumSize and getPreferredSize methods return the same value, SpringLayout interprets this as meaning that the component should not be stretched. JLabel and JButton are examples of components implemented this way. For this reason, the label in the SpringDemo3 example does not stretch.

The getMaximumSize method of some components, such as JTextField, returns the value Integer.MAX_VALUE for the width and height of its maximum size, indicating that the component can grow to any size. For this reason, when the SpringDemo3 window is enlarged, SpringLayout distributes all the extra space to the only springs that can grow — those determining the size of the text field.

More About the SpringLayout API

The SpringDemo examples used the SpringLayout method putConstraint to set the springs associated with each component. The putConstraint method is a convenience method that lets you modify a component's constraints without needing to use the full spring layout API. Here, again, is the code from SpringDemo3 that sets the location of the label:

layout.putConstraint(SpringLayout.WEST, label,
                     5,
                     SpringLayout.WEST, contentPane);
layout.putConstraint(SpringLayout.NORTH, label,
                     5,
                     SpringLayout.NORTH, contentPane);
Here is equivalent code that uses the SpringLayout.Constraints and Spring classes directly:

SpringLayout.Constraints  contentPaneCons = 
        layout.getConstraints(contentPane);
contentPaneCons.setX(Spring.sum(Spring.constant(5),
                          contentPaneCons
                          .getConstraint(SpringLayout.WEST)));
contentPaneCons.setY(Spring.sum(Spring.constant(5),
                          contentPaneCons
                          .getConstraint(SpringLayout.NORTH)));

To see the entire demo converted to use this API, look at SpringDemo4.java. That file also includes a more polished (and much longer) version of the code that sets the container's size. Click the Launch button to run SpringDemo4 using Java™ Web Start (download JDK 7 or later). Alternatively, to compile and run the example yourself, consult the example index.

Launches the SpringDemo4 example

As the preceding snippets imply, SpringLayout and SpringLayout.Constraints tend to use different conventions for describing springs. The SpringLayout API uses edges to define its constraints. Springs connect edges to establish linear relations between them. Edges are defined by components, using the following constants:

◉ SpringLayout.NORTH specifies the top edge of a component's bounding rectangle.
◉ SpringLayout.SOUTH specifies the bottom edge of a component's bounding rectangle.
◉ SpringLayout.EAST specifies the right edge of a component's bounding rectangle.
◉ SpringLayout.WEST specifies the left edge of a component's bounding rectangle.
◉ SpringLayout.BASELINE specifies the baseline of a component.
◉ SpringLayout.HORIZONTAL_CENTER specifies the horizontal center of a component's bounding rectangle.
◉ SpringLayout.VERTICAL_CENTER specifies the vertical center of a component's bounding rectangle.

Edges differ from Spring objects The SpringLayout.Constraints class knows about edges, but only has Spring objects for the following properties:

◉ x
◉ y
◉ width
◉ height

Each Constraints object maintains the following relationships between its springs and the edges they represent:

 west = x
north = y
 east = x + width
south = y + height

If you are confused, do not worry. The next section presents utility methods you can use to accomplish some common layout tasks without knowing anything about the spring layout API.

Utility Methods for Grids

Because the SpringLayout class was created for GUI builders, setting up individual springs for a layout can be cumbersome to code by hand. This section presents a couple of methods you can use to install all the springs needed to lay out a group of components in a grid. These methods emulate some of the features of the GridLayout, GridBagLayout, and BoxLayout classes.

The two methods, called makeGrid and makeCompactGrid, are defined in SpringUtilities.java. Both methods work by grouping the components together into rows and columns and using the Spring.max method to make a width or height spring that makes a row or column big enough for all the components in it. In the makeCompactGrid method the same width or height spring is used for all components in a particular column or row, respectively. In the makeGrid method, by contrast, the width and height springs are shared by every component in the container, forcing them all to be the same size. Furthermore, factory methods are provided by Spring for creating different kinds of springs, including springs that depend on other springs.

Let us see these methods in action. Our first example, implemented in the source file SpringGrid.java, displays a bunch of numbers in text fields. The center text field is much wider than the others. Just as with GridLayout, having one large cell forces all the cells to be equally large. Click the Launch button to run SpringGrid using Java™ Web Start (download JDK 7 or later). 

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Here is the code that creates and lays out the text fields in SpringGrid:

JPanel panel = new JPanel(new SpringLayout());
for (int i = 0; i < 9; i++) {
    JTextField textField = new JTextField(Integer.toString(i));
    ...//when i==4, put long text in the text field...
    panel.add(textField);
}
...
SpringUtilities.makeGrid(panel,
                         3, 3, //rows, cols
                         5, 5, //initialX, initialY
                         5, 5);//xPad, yPad

Now let us look at an example, in the source file SpringCompactGrid.java, that uses the makeCompactGrid method instead of makeGrid. This example displays lots of numbers to show off spring layout's ability to minimize the space required. Click the Launch button to run SpringCompactGrid using Java™ Web Start (download JDK 7 or later).

Here is what the SpringCompactGrid GUI looks like:

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Here is the code that creates and lays out the text fields in SpringCompactGrid:

JPanel panel = new JPanel(new SpringLayout());

int rows = 10;
int cols = 10;
for (int r = 0; r < rows; r++) {
    for (int c = 0; c < cols; c++) {
        int anInt = (int) Math.pow(r, c);
        JTextField textField =
                new JTextField(Integer.toString(anInt));
        panel.add(textField);
    }
}

//Lay out the panel.
SpringUtilities.makeCompactGrid(panel, //parent
                                rows, cols,
                                3, 3,  //initX, initY
                                3, 3); //xPad, yPad

One of the handiest uses for the makeCompactGrid method is associating labels with components, where the labels are in one column and the components in another. The file SpringForm.java uses makeCompactGrid in this way, as the following figure demonstrates.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Click the Launch button to run SpringForm using Java™ Web Start (download JDK 7 or later).

Here is the code that creates and lays out the label-text field pairs in SpringForm:

String[] labels = {"Name: ", "Fax: ", "Email: ", "Address: "};
int numPairs = labels.length;

//Create and populate the panel.
JPanel p = new JPanel(new SpringLayout());
for (int i = 0; i < numPairs; i++) {
    JLabel l = new JLabel(labels[i], JLabel.TRAILING);
    p.add(l);
    JTextField textField = new JTextField(10);
    l.setLabelFor(textField);
    p.add(textField);
}

//Lay out the panel.
SpringUtilities.makeCompactGrid(p,
                                numPairs, 2, //rows, cols
                                6, 6,        //initX, initY
                                6, 6);       //xPad, yPad

Because we are using a real layout manager instead of absolute positioning, the layout manager responds dynamically to changes in components involved. For example, if the names of the labels are localized, the spring layout produces a configuration that gives the first column more or less room, as needed. And as the following figure shows, when the window is resized, the flexibly sized components — the text fields — take all the excess space, while the labels stick to what they need.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Our last example of the makeCompactGrid method, in SpringBox.java, shows some buttons configured to be laid out in a single row. Click the Launch button to run SpringBox using Java™ Web Start (download JDK 7 or later).

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Note that the behavior is almost identical to that of BoxLayout in the case of a single row. Not only are the components laid out as BoxLayout would arrange them but the minimum, preferred, and maximum sizes of the container that uses the SpringLayout return the same results that BoxLayout would. Here is the call to makeCompactGrid that produces this layout:

//Lay out the buttons in one row and as many columns
//as necessary, with 6 pixels of padding all around.
SpringUtilities.makeCompactGrid(contentPane, 1,
                                contentPane.getComponentCount(),
                                6, 6, 6, 6);
Let us look at what happens when we resize this window. This is an odd special case that is worth taking note of as you may run into it by accident in your first layouts.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Nothing moved! That is because none of the components (buttons) or the spacing between them was defined to be stretchable. In this case the spring layout calculates a maximum size for the parent container that is equal to its preferred size, meaning the parent container itself is not stretchable. It would perhaps be less confusing if the AWT refused to resize a window that was not stretchable, but it does not. The layout manager cannot do anything sensible here as none of the components will take up the required space. Instead of crashing, it just does nothing, leaving all the components as they were.

The SpringLayout API


The API for using SpringLayout is spread across three classes:

SpringLayout

Constructor or Method Create a SpringLayout instance. 
SpringLayout() Get the constraints (set of springs) associated with the specified component.
SpringLayout.Constraints getConstraints(Component) Get the spring for an edge of a component. The first argument specifies the edge and must be one of the following SpringLayout constants: NORTH, SOUTH, EAST, or WEST.
Spring getConstraint(String, Component) Get the spring for an edge of a component. The first argument specifies the edge and must be one of the following SpringLayout constants: NORTH, SOUTH, EAST, or WEST.
void putConstraint(String, Component, int, String, Component)
void putConstraint(String, Component, Spring, String, Component)
Convenience methods for defining relationships between the edges of two components. The first two arguments specify the first component and its affected edge. The last two arguments specify the second component and its affected edge. The third argument specifies the spring that determines the distance between the two. When the third argument is an integer, a constant spring is created to provide a fixed distance between the component edges.

SpringLayout.Constraints

Constructor or Method Create a SpringLayout instance. 
SpringLayout.Constraints()
SpringLayout.Constraints(Spring, Spring)
SpringLayout.Constraints(Spring, Spring, Spring, Spring)
Create a SpringLayout.Constraints instance. The first two arguments, if present, specify the X and Y springs, respectively. The second two arguments, if present, specify the height and width springs, respectively. Omitting an argument causes the corresponding spring to be null, which SpringLayout generally replaces with suitable defaults.
Spring getConstraint(String)
Spring getHeight()
Spring getWidth()
Spring getX()
Spring getY()
void setConstraint(String, Spring)
void setHeight(Spring)
void setWidth(Spring)
void setX(Spring)
void setY(Spring)
Get or set the specified spring. The string argument to the getConstraint and setConstraint methods specifies an edge name, and must be one of the SpringLayout constants NORTH, SOUTH, EAST, or WEST.

Spring

Method Purpose
static Spring constant(int)
static Spring constant(int, int, int)
Create a spring that does not track a component's sizes. The three-argument version creates a spring with its minimum, preferred, and maximum values set to the specified values, in that order. The one-argument version creates a spring with its minimum, preferred, and maximum values all set to the specified integer.
Despite the name, springs returned by constant are mutable. To make a layout work out, SpringLayout might be forced to adjust a "constant" spring. For this reason, you should avoid reusing constant springs unless (1) you truly want the springs to always be precisely alike and (2) other springs provide some flexibility in the layout.
static Spring sum(Spring, Spring)
static Spring max(Spring, Spring)
static Spring minus(Spring)
Create a spring that is the result of some mathematical manipulation. The sum method adds two springs. The max method returns a spring whose value is always greater than or equal to the values of the two arguments. The minus method returns a spring running in the opposite direction of the argument. The minus method can be used to create an argument for the sum method, allowing you to get the difference between two springs.
int getMinimumValue()
int getPreferredValue()
int getMaximumValue()
Get the corresponding value from the spring. For a SpringLayout-created spring that automatically tracks a component, these methods result in calls to the component's corresponding getXxxSize method.
int getValue()
setValue(int)
Get or set the spring's current value.

Examples that Use SpringLayout

The following table lists some examples that use spring layout.

Example Where Described Notes
SpringDemo3 This Page Uses SpringLayout to create a row of evenly spaced, natural-size components.
SpringDemo4 This Page  Reimplements SpringDemo3 to use SpringLayout.Constraints and Spring directly.
SpringGrid This Page  Uses SpringLayout and the makeGrid utility method to create a layout where all the components are the same size.
SpringCompactGrid This Page  Uses SpringLayout and the makeCompactGrid utility method to create a layout where all the components in a row have the same height, and all components in a column have the same width.
SpringForm This Page  Uses SpringLayout and makeCompactGrid to align label-text field pairs.
SpringBox This Page Uses SpringLayout and makeCompactGrid to demonstrate laying out a single row of components, and what happens when no springs can grow.
SpinnerDemo How to Use Spinners Uses SpringLayout and makeCompactGrid to lay out rows of label-spinner pairs.
TextInputDemo How to Use Formatted Text Fields Uses SpringLayout and makeCompactGrid to lay out rows of labeled components. The components are a mix of text fields, formatted text fields, and spinners.

◉ Creating a Custom Layout Manager


Before you start creating a custom layout manager, make sure that no existing layout manager meets your requirements. In particular, layout managers such as GridBagLayout, SpringLayout, and BoxLayout are flexible enough to work in many cases. You can also find layout managers from other sources, such as from the Internet. Finally, you can simplify layout by grouping components into containers such as panels.

Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.
If you are interested in using JavaFX to create your GUI, see Working With Layouts in JavaFX.

To create a custom layout manager, you must create a class that implements the LayoutManager interface. You can either implement it directly, or implement its subinterface, LayoutManager2.

Every layout manager must implement at least the following five methods, which are required by the LayoutManager interface:

void addLayoutComponent(String, Component)

Called by the Container class's add methods. Layout managers that do not associate strings with their components generally do nothing in this method.

void removeLayoutComponent(Component)

Called by the Container methods remove and removeAll. Layout managers override this method to clear an internal state they may have associated with the Component.

Dimension preferredLayoutSize(Container)

Called by the Container class's getPreferredSize method, which is itself called under a variety of circumstances. This method should calculate and return the ideal size of the container, assuming that the components it contains will be at or above their preferred sizes. This method must take into account the container's internal borders, which are returned by the getInsets method.

Dimension minimumLayoutSize(Container)

Called by the Container getMinimumSize method, which is itself called under a variety of circumstances. This method should calculate and return the minimum size of the container, assuming that the components it contains will be at or above their minimum sizes. This method must take into account the container's internal borders, which are returned by the getInsets method.

void layoutContainer(Container)

Called to position and size each of the components in the container. A layout manager's layoutContainer method does not actually draw components. It simply invokes one or more of each component's setSize, setLocation, and setBounds methods to set the component's size and position.

This method must take into account the container's internal borders, which are returned by the getInsets method. If appropriate, it should also take the container's orientation (returned by the getComponentOrientation method) into account. You cannot assume that the preferredLayoutSize or minimumLayoutSize methods will be called before layoutContainer is called.

Besides implementing the preceding five methods, layout managers generally implement at least one public constructor and the toString method.

If you wish to support component constraints, maximum sizes, or alignment, then your layout manager should implement the LayoutManager2 interface. In fact, for these reasons among many others, nearly all modern layout managers will need to implement LayoutManager2. That interface adds five methods to those required by LayoutManager:

◉ addLayoutComponent(Component, Object)
◉ getLayoutAlignmentX(Container)
◉ getLayoutAlignmentY(Container)
◉ invalidateLayout(Container)
◉ maximumLayoutSize(Container)

Of these methods, the most important are addLayoutComponent(Component, Object) and invalidateLayout(Container). The addLayoutComponent method is used to add components to the layout, using the specified constraint object. The invalidateLayout method is used to invalidate the layout, so that if the layout manager has cached information, this should be discarded. For more information about LayoutManager2, see the LayoutManager2 API documentation.

Finally, whenever you create custom layout managers, you should be careful of keeping references to Component instances that are no longer children of the Container. Namely, layout managers should override removeLayoutComponent to clear any cached state related to the Component.

Example of a Custom Layout

The example CustomLayoutDemo uses a custom layout manager called DiagonalLayout. You can find the layout manager's source code in DiagonalLayout.java. DialogLayout lays out components diagonally, from left to right, with one component per row. Here is a picture of CustomLayoutDemo using DialogLayout to lay out five buttons.

Oracle Java Tutorials and Materials, Oracle Certifications, Java Guides

Click the Launch button to run CustomLayoutDemo using Java™ Web Start (download JDK 7 or later). 

◉ Doing Without a Layout Manager (Absolute Positioning)


Although it is possible to do without a layout manager, you should use a layout manager if at all possible. A layout manager makes it easier to adjust to look-and-feel-dependent component appearances, to different font sizes, to a container's changing size, and to different locales. Layout managers also can be reused easily by other containers, as well as other programs.

Note: This lesson covers writing layout code by hand, which can be challenging. If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager.

If you are interested in using JavaFX to create your GUI.

If a container holds components whose size is not affected by the container's size or by font, look-and-feel, or language changes, then absolute positioning might make sense. Desktop panes, which contain internal frames, are in this category. The size and position of internal frames does not depend directly on the desktop pane's size. The programmer determines the initial size and placement of internal frames within the desktop pane, and then the user can move or resize the frames. A layout manager is unnecessary in this situation.

Another situation in which absolute positioning might make sense is that of a custom container that performs size and position calculations that are particular to the container, and perhaps require knowledge of the container's specialized state. This is the situation with split panes.

Creating a container without a layout manager involves the following steps.

1. Set the container's layout manager to null by calling setLayout(null).
2. Call the Component class's setbounds method for each of the container's children.
3. Call the Component class's repaint method.

However, creating containers with absolutely positioned containers can cause problems if the window containing the container is resized.


Here is a snapshot of a frame whose content pane uses absolute positioning.

Oracle Java Tutorials and Materials

Click the Launch button to run AbsoluteLayoutDemo using Java™ Web Start (download JDK 7 or later).

Its code is in AbsoluteLayoutDemo.java. The following code snippet shows how the components in the content pane are created and laid out.

pane.setLayout(null);

JButton b1 = new JButton("one");
JButton b2 = new JButton("two");
JButton b3 = new JButton("three");

pane.add(b1);
pane.add(b2);
pane.add(b3);

Insets insets = pane.getInsets();
Dimension size = b1.getPreferredSize();
b1.setBounds(25 + insets.left, 5 + insets.top,
             size.width, size.height);
size = b2.getPreferredSize();
b2.setBounds(55 + insets.left, 40 + insets.top,
             size.width, size.height);
size = b3.getPreferredSize();
b3.setBounds(150 + insets.left, 15 + insets.top,
             size.width + 50, size.height + 20);

...//In the main method:
Insets insets = frame.getInsets();
frame.setSize(300 + insets.left + insets.right,
              125 + insets.top + insets.bottom);

«« Previous
Next »»