|
|
|
Contents: |
|
|
|
Related content: |
|
|
|
Subscriptions: |
|
|
| When GridBagLayout isn't enough
John
Zukowski (mailto:jaz@zukowski.net?cc=&subject=SpringLayout
manager) President, JZ Ventures, Inc. 17 September 2003
Many developers try to avoid the powerful
GridBagLayout manager when designing complex screens.
Instead of fiddling with the GridBagConstraints , they embed
panels inside panels with different layout managers like
BorderLayout . The newly introduced
SpringLayout manager offers an alternative in which
components are positioned relative to one another. In this article,
Merlin veteran John Zukowski shows you how to use this new layout
manager. Share your thoughts on this article with the author and other
readers in the accompanying discussion forum. (You
can also click Discuss at the top or
bottom of the article to access the
forum.)
The newest addition on the Java layout manager front is the
SpringLayout manager, added with the Java 1.4 release. This
layout manager allows you to attach "springs" to components so that they
can be laid out relative to other components. For instance, with
SpringLayout , you can say that a button appears attached to
the right border, no matter what size a user makes the screen.
Getting started with
SpringLayout Like all layout managers, the
SpringLayout manager is responsible for positioning
components. Component positions are controlled by associating constraints
to them. For SpringLayout -controlled components, there is one
constraint with four settings -- one for each edge of the component. The
SpringLayout manager relies on a
SpringLayout.Constraints object for these component
constraints. This works similar to the GridBagConstraints
class that complements the GridBagLayout manager: Each
component added to the container can have an attached
SpringLayout.Constraints object. This, however, is where the
similarities end.
While with GridBagLayout , you typically add the component
to the container with the constraints, in the case of the
SpringLayout manager, you usually don't have to add the
component with the constraints. Instead, you can add the component and
then attach the constraints separately. There is nothing stopping you from
adding the constraints with the component, but
SpringLayout.Constraints is not a simple class. It is a
collection of Spring objects (for each edge), each being a
different constraint on the component. When you use it, you need to add
each Spring constraint separately to
SpringLayout.Constraints . You "add" constraints to
SpringLayout.Constraints by setting specific constraints on
an edge of the component. Using the four SpringLayout
constants of EAST , WEST , NORTH , and
SOUTH , you call the setContraints(String edge, Spring
spring) method of SpringLayout.Constraints , where
String is one of the constants. For instance, if you wanted
to add a component in the top-left of a container, you could set up two
springs of constant size, combine them together, and add the component to
the container with the combined set, as shown here in Listing 1: Listing 1. Working with SpringLayout
Component left = ...;
SpringLayout layout = new SpringLayout();
JPanel panel = new JPanel(layout);
Spring xPad = Spring.constant(5);
Spring yPad = Spring.constant(25);
SpringLayout.Constraints constraint = new SpringLayout.Constraints();
constraint.setConstraint(SpringLayout.WEST, xPad);
constraint.setConstraint(SpringLayout.NORTH, yPad);
contentPane.add(left, constraint);
|
That may not look particularly difficult, but it gets harder when you
need to add the next component, either to the right of the first or below
it. You can't just add the component n pixels over; you
actually must add the padding to the edge of the earlier component. To
find the edge of the earlier component, you ask the layout manager with
getConstraint() , passing in the edge you want and the
component, as in layout.getConstraint(SpringLayout.EAST,
left) , to get the location of the right edge of the first
component. From that, you can add in the necessary padding and attach it
to the edge of the other component, as shown in Listing 2: Listing 2. Adding the second component with
SpringLayout
Component right = ...;
Spring rightSideOfLeft = layout.getConstraint(SpringLayout.EAST, left);
Spring pad = Spring.constant(20);
Spring leftEdgeOfRight = Spring.sum(rightSideOfLeft, pad);
constraint = new SpringLayout.Constraints();
constraint.setConstraint(SpringLayout.WEST, leftEdgeOfRight);
constraint.setConstraint(SpringLayout.NORTH, yPad);
contentPane.add(right, constraint);
|
Using putConstraint() with
SpringLayout This approach works perfectly well, but gets
tedious as the number of components increases. Instead, another way that
sidesteps the in-between steps is to add the components without the
constraints and then add each separately, using the
putConstraint() method of SpringLayout to
connect the components, as shown in Listing 3: Listing 3. Adding the second component with
SpringLayout
public void putConstraint(String e1, Component c1, int pad,
String e2, Component c2)
public void putConstraint(String e1, Component c1, Spring s,
String e2, Component c2)
|
Here, instead of asking for the edge and adding in the padding
yourself, the putConstraint() call combines the tasks for
you. To demonstrate, Listing 4 adds the same component constraints to the
right component as Listing 3, but uses putConstraint()
instead of SpringLayout.Constraints directly: Listing 4. Using putConstraint() to add the second
component
Component left = ...;
Component right = ...;
SpringLayout layout = new SpringLayout();
JPanel panel = new JPanel(layout);
panel.add(left);
panel.add(right);
layout.putConstraint(SpringLayout.WEST, left, 5,
SpringLayout.WEST, panel);
layout.putConstraint(SpringLayout.NORTH, left, 25,
SpringLayout.NORTH, panel);
layout.putConstraint(SpringLayout.NORTH, right, 25,
SpringLayout.NORTH, panel);
layout.putConstraint(SpringLayout.WEST, right, 20,
SpringLayout.EAST, left);
|
The String arguments of putConstraint() are the four
SpringLayout constants EAST, WEST, NORTH, and SOUTH. When you
use putConstraint() , be sure to specify the unknown component
position first and connect it to something that can be calculated or is
fixed, like the edge of the screen.
Trying out SpringLayout with
BeanBuilder To help you visualize the use of
SpringLayout , Sun has a tool available called BeanBuilder
(see Resources). The tool is
meant more to be used when working with JavaBeans components, but it also
offers an easy way to explore SpringLayout . Figure 1 shows
what the tool looks like on startup:
Figure 1. BeanBuilder startup screen
While we're not going to talk about the specifics of the tool, one
thing BeanBuilder does let you do is connect components with
SpringLayout . Around the edges of each component are a set of
four boxes, one each for north, south, east, and west. You can drag an
arrow out of a box and connect it to any other box. If the tool were a
little more sophisticated, it would permit you to specify gap sizes, but
Figure 2 shows what a screen might look like during development:
Figure 2. BeanBuilder usage screen
As Figure 2 illustrates, you can visually connect the arrow to a
specific putConstraint() call.
Complete SpringLayout
example To demonstrate the use of SpringLayout ,
Listing 4 is the SpringFormTest program that connects the pieces explained
using putConstraint() . (You can also download this code; see
Resources.) Listing 4. Complete SpringLayout example
import java.awt.*;
import javax.swing.*;
public class SpringFormTest {
public static void main(String args[]) {
JFrame frame = new JFrame("Spring Form");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
SpringLayout layout = new SpringLayout();
contentPane.setLayout(layout);
Component left = new JLabel("Left");
Component right = new JTextField(15);
contentPane.add(left);
contentPane.add(right);
layout.putConstraint(SpringLayout.WEST, left, 10,
SpringLayout.WEST, contentPane);
layout.putConstraint(SpringLayout.NORTH, left, 25,
SpringLayout.NORTH, contentPane);
layout.putConstraint(SpringLayout.NORTH, right, 25,
SpringLayout.NORTH, contentPane);
layout.putConstraint(SpringLayout.WEST, right, 20,
SpringLayout.EAST, left);
frame.setSize(300, 100);
frame.show();
}
}
|
Figure 3 shows the results:
Figure 3. SpringFormTest example
screen
Resources
|
|