SpringLayoutpublic class SpringLayout extends Object implements LayoutManager2A SpringLayout lays out the children of its associated container
according to a set of constraints.
See How to Use SpringLayout
in The Java Tutorial for examples of using
SpringLayout .
Each constraint,
represented by a Spring object,
controls the vertical or horizontal distance
between two component edges.
The edges can belong to
any child of the container,
or to the container itself.
For example,
the allowable width of a component
can be expressed using a constraint
that controls the distance between the west (left) and east (right)
edges of the component.
The allowable y coordinates for a component
can be expressed by constraining the distance between
the north (top) edge of the component
and the north edge of its container.
Every child of a SpringLayout -controlled container,
as well as the container itself,
has exactly one set of constraints
associated with it.
These constraints are represented by
a SpringLayout.Constraints object.
By default,
SpringLayout creates constraints
that make their associated component
have the minimum, preferred, and maximum sizes
returned by the component's
{@link java.awt.Component#getMinimumSize},
{@link java.awt.Component#getPreferredSize}, and
{@link java.awt.Component#getMaximumSize}
methods. The x and y positions are initially not
constrained, so that until you constrain them the Component
will be positioned at 0,0 relative to the Insets of the
parent Container .
You can change
a component's constraints in several ways.
You can
use one of the
{@link #putConstraint putConstraint}
methods
to establish a spring
linking the edges of two components within the same container.
Or you can get the appropriate SpringLayout.Constraints
object using
{@link #getConstraints getConstraints}
and then modify one or more of its springs.
Or you can get the spring for a particular edge of a component
using {@link #getConstraint getConstraint},
and modify it.
You can also associate
your own SpringLayout.Constraints object
with a component by specifying the constraints object
when you add the component to its container
(using
{@link Container#add(Component, Object)}).
The Spring object representing each constraint
has a minimum, preferred, maximum, and current value.
The current value of the spring
is somewhere between the minimum and maximum values,
according to the formula given in the
{@link Spring#sum} method description.
When the minimum, preferred, and maximum values are the same,
the current value is always equal to them;
this inflexible spring is called a strut.
You can create struts using the factory method
{@link Spring#constant(int)}.
The Spring class also provides factory methods
for creating other kinds of springs,
including springs that depend on other springs.
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.
Springs should only be attached
between edges of the container and its immediate children; the behavior
of the SpringLayout when presented with constraints linking
the edges of components from different containers (either internal or
external) is undefined.
SpringLayout vs. Other Layout Managers
Note:
Unlike many layout managers,
SpringLayout doesn't 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.
Despite the simplicity of SpringLayout ,
it can emulate the behavior of most other layout managers.
For some features,
such as the line breaking provided by FlowLayout ,
you'll need to
create a special-purpose subclass of the Spring class.
SpringLayout also provides a way to solve
many of the difficult layout
problems that cannot be solved by nesting combinations
of Box es. That said, SpringLayout honors the
LayoutManager2 contract correctly and so can be nested with
other layout managers -- a technique that can be preferable to
creating the constraints implied by the other layout managers.
The asymptotic complexity of the layout operation of a SpringLayout
is linear in the number of constraints (and/or components).
Warning:
Serialized objects of this class will not be compatible with
future Swing releases. The current serialization support is
appropriate for short term storage or RMI between applications running
the same version of Swing. As of 1.4, support for long term storage
of all JavaBeansTM
has been added to the java.beans package.
Please see {@link java.beans.XMLEncoder}. |
Fields Summary |
---|
private Map | componentConstraints | private Spring | cyclicReference | private Set | cyclicSprings | private Set | acyclicSprings | public static final String | NORTHSpecifies the top edge of a component's bounding rectangle. | public static final String | SOUTHSpecifies the bottom edge of a component's bounding rectangle. | public static final String | EASTSpecifies the right edge of a component's bounding rectangle. | public static final String | WESTSpecifies the left edge of a component's bounding rectangle. |
Constructors Summary |
---|
public SpringLayout()Constructs a new SpringLayout .
|
Methods Summary |
---|
private javax.swing.Spring | abandonCycles(javax.swing.Spring s)
return isCyclic(s) ? cyclicReference : s;
| private static java.awt.Dimension | addInsets(int width, int height, java.awt.Container p)
Insets i = p.getInsets();
return new Dimension(width + i.left + i.right, height + i.top + i.bottom);
| public void | addLayoutComponent(java.awt.Component component, java.lang.Object constraints)If constraints is an instance of
SpringLayout.Constraints ,
associates the constraints with the specified component.
if (constraints instanceof Constraints) {
putConstraints(component, (Constraints)constraints);
}
| public void | addLayoutComponent(java.lang.String name, java.awt.Component c)Has no effect,
since this layout manager does not
use a per-component string.
| private javax.swing.SpringLayout$Constraints | applyDefaults(java.awt.Component c, javax.swing.SpringLayout$Constraints constraints)
if (constraints == null) {
constraints = new Constraints();
}
if (constraints.getWidth() == null) {
constraints.setWidth(new Spring.WidthSpring(c));
}
if (constraints.getHeight() == null) {
constraints.setHeight(new Spring.HeightSpring(c));
}
if (constraints.getX() == null) {
constraints.setX(Spring.constant(0));
}
if (constraints.getY() == null) {
constraints.setY(Spring.constant(0));
}
return constraints;
| public javax.swing.Spring | getConstraint(java.lang.String edgeName, java.awt.Component c)Returns the spring controlling the distance between
the specified edge of
the component and the top or left edge of its parent. This
method, instead of returning the current binding for the
edge, returns a proxy that tracks the characteristics
of the edge even if the edge is subsequently rebound.
Proxies are intended to be used in builder envonments
where it is useful to allow the user to define the
constraints for a layout in any order. Proxies do, however,
provide the means to create cyclic dependencies amongst
the constraints of a layout. Such cycles are detected
internally by SpringLayout so that
the layout operation always terminates.
// The interning here is unnecessary; it was added for efficiency.
edgeName = edgeName.intern();
return new SpringProxy(edgeName, c, this);
| public javax.swing.SpringLayout$Constraints | getConstraints(java.awt.Component c)Returns the constraints for the specified component.
Note that,
unlike the GridBagLayout
getConstraints method,
this method does not clone constraints.
If no constraints
have been associated with this component,
this method
returns a default constraints object positioned at
0,0 relative to the parent's Insets and its width/height
constrained to the minimum, maximum, and preferred sizes of the
component. The size characteristics
are not frozen at the time this method is called;
instead this method returns a constraints object
whose characteristics track the characteristics
of the component as they change.
Constraints result = (Constraints)componentConstraints.get(c);
if (result == null) {
if (c instanceof javax.swing.JComponent) {
Object cp = ((javax.swing.JComponent)c).getClientProperty(SpringLayout.class);
if (cp instanceof Constraints) {
return applyDefaults(c, (Constraints)cp);
}
}
result = new Constraints();
putConstraints(c, result);
}
return result;
| public float | getLayoutAlignmentX(java.awt.Container p)Returns 0.5f (centered).
return 0.5f;
| public float | getLayoutAlignmentY(java.awt.Container p)Returns 0.5f (centered).
return 0.5f;
| public void | invalidateLayout(java.awt.Container p)
| boolean | isCyclic(javax.swing.Spring s)
if (s == null) {
return false;
}
if (cyclicSprings.contains(s)) {
return true;
}
if (acyclicSprings.contains(s)) {
return false;
}
cyclicSprings.add(s);
boolean result = s.isCyclic(this);
if (!result) {
acyclicSprings.add(s);
cyclicSprings.remove(s);
}
else {
System.err.println(s + " is cyclic. ");
}
return result;
| public void | layoutContainer(java.awt.Container parent)
setParent(parent);
int n = parent.getComponentCount();
getConstraints(parent).reset();
for (int i = 0 ; i < n ; i++) {
getConstraints(parent.getComponent(i)).reset();
}
Insets insets = parent.getInsets();
Constraints pc = getConstraints(parent);
abandonCycles(pc.getX()).setValue(0);
abandonCycles(pc.getY()).setValue(0);
abandonCycles(pc.getWidth()).setValue(parent.getWidth() -
insets.left - insets.right);
abandonCycles(pc.getHeight()).setValue(parent.getHeight() -
insets.top - insets.bottom);
for (int i = 0 ; i < n ; i++) {
Component c = parent.getComponent(i);
Constraints cc = getConstraints(c);
int x = abandonCycles(cc.getX()).getValue();
int y = abandonCycles(cc.getY()).getValue();
int width = abandonCycles(cc.getWidth()).getValue();
int height = abandonCycles(cc.getHeight()).getValue();
c.setBounds(insets.left + x, insets.top + y, width, height);
}
| public java.awt.Dimension | maximumLayoutSize(java.awt.Container parent)
setParent(parent);
Constraints pc = getConstraints(parent);
return addInsets(abandonCycles(pc.getWidth()).getMaximumValue(),
abandonCycles(pc.getHeight()).getMaximumValue(),
parent);
| public java.awt.Dimension | minimumLayoutSize(java.awt.Container parent)
setParent(parent);
Constraints pc = getConstraints(parent);
return addInsets(abandonCycles(pc.getWidth()).getMinimumValue(),
abandonCycles(pc.getHeight()).getMinimumValue(),
parent);
| public java.awt.Dimension | preferredLayoutSize(java.awt.Container parent)
setParent(parent);
Constraints pc = getConstraints(parent);
return addInsets(abandonCycles(pc.getWidth()).getPreferredValue(),
abandonCycles(pc.getHeight()).getPreferredValue(),
parent);
| public void | putConstraint(java.lang.String e1, java.awt.Component c1, int pad, java.lang.String e2, java.awt.Component c2)Links edge e1 of component c1 to
edge e2 of component c2 ,
with a fixed distance between the edges. This
constraint will cause the assignment
value(e1, c1) = value(e2, c2) + pad
to take place during all subsequent layout operations.
putConstraint(e1, c1, Spring.constant(pad), e2, c2);
| public void | putConstraint(java.lang.String e1, java.awt.Component c1, javax.swing.Spring s, java.lang.String e2, java.awt.Component c2)Links edge e1 of component c1 to
edge e2 of component c2 . As edge
(e2, c2) changes value, edge (e1, c1) will
be calculated by taking the (spring) sum of (e2, c2)
and s . Each edge must have one of the following values:
SpringLayout.NORTH , SpringLayout.SOUTH ,
SpringLayout.EAST , SpringLayout.WEST .
putConstraint(e1, c1, Spring.sum(s, getConstraint(e2, c2)));
| private void | putConstraint(java.lang.String e, java.awt.Component c, javax.swing.Spring s)
if (s != null) {
getConstraints(c).setConstraint(e, s);
}
| private void | putConstraints(java.awt.Component component, javax.swing.SpringLayout$Constraints constraints)
componentConstraints.put(component, applyDefaults(component, constraints));
| public void | removeLayoutComponent(java.awt.Component c)Removes the constraints associated with the specified component.
componentConstraints.remove(c);
| private void | resetCyclicStatuses()
cyclicSprings = new HashSet();
acyclicSprings = new HashSet();
| private void | setParent(java.awt.Container p)
resetCyclicStatuses();
Constraints pc = getConstraints(p);
pc.setX(Spring.constant(0));
pc.setY(Spring.constant(0));
// The applyDefaults() method automatically adds width and
// height springs that delegate their calculations to the
// getMinimumSize(), getPreferredSize() and getMaximumSize()
// methods of the relevant component. In the case of the
// parent this will cause an infinite loop since these
// methods, in turn, delegate their calculations to the
// layout manager. Check for this case and replace the
// the springs that would cause this problem with a
// constant springs that supply default values.
Spring width = pc.getWidth();
if (width instanceof Spring.WidthSpring && ((Spring.WidthSpring)width).c == p) {
pc.setWidth(Spring.constant(0, 0, Integer.MAX_VALUE));
}
Spring height = pc.getHeight();
if (height instanceof Spring.HeightSpring && ((Spring.HeightSpring)height).c == p) {
pc.setHeight(Spring.constant(0, 0, Integer.MAX_VALUE));
}
|
|