JDK-4726194 : SpringLayout doesn't always resolve constraints correctly
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2002-08-05
  • Updated: 2017-05-16
  • Resolved: 2005-09-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6
6 b53Fixed
Description
Name: pa48320			Date: 08/05/2002


FULL PRODUCT VERSION :
java version "1.4.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)

and

java version "1.4.1-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-beta-b14)
Java HotSpot(TM) Client VM (build 1.4.1-beta-b14, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows XP [Version 5.1.2600]

ADDITIONAL OPERATING SYSTEMS :
Red Hat Linux release 7.3 (Valhalla)
#1 SMP Thu Apr 18 07:17:10 EDT 2002
2.4.18-3bigmem



A DESCRIPTION OF THE PROBLEM :
SpringLayout fails to properly evaluate constraints under
many conditions, one of them being that the order in which
constraints are attached is significant. The attached
reproduction is a trivial example with a known workaround.
However, for many of the non-trivial layouts we have tried
to use in a production system there are no known
workarounds.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run this attached source code.
2. Swap constraints A and B and run it again.
3. Note the different behavior.

EXPECTED VERSUS ACTUAL BEHAVIOR :
In step 1, the text field collapses to width 0 and tracks
the East edge of the parent. It should conform to both
constraints and resize appropriately, as it does in step
3. In the general case, any legal set of constraints
should be obeyed, but they are not.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package test;

import javax.swing.*;

public class TestSpring extends JPanel {

  public TestSpring() {
        SpringLayout m_layout = new SpringLayout();
        setLayout(m_layout);
        Spring margin = Spring.constant(5);

        JLabel m_lName = new JLabel("Label");
        add(m_lName);
        SpringLayout.Constraints cons = m_layout.getConstraints(m_lName);
        cons.setX(margin);
        cons.setY(margin);
        cons.setWidth(Spring.constant(60));

        JTextField m_tName = new JTextField();
        add(m_tName);
        cons = m_layout.getConstraints(m_tName);
        cons.setY(margin);
        // Constraint A
        m_layout.putConstraint(SpringLayout.WEST, m_tName, 5,
                               SpringLayout.EAST, m_lName);
        // Constraint B
        m_layout.putConstraint(SpringLayout.EAST, m_tName, -5,
                               SpringLayout.EAST, this);

        m_layout.layoutContainer(this);
  }

   public static void main(String[] args) {
     JFrame jf = new JFrame("Test SpringLayout");
     jf.setDefaultCloseOperation(jf.EXIT_ON_CLOSE);
     jf.getContentPane().add(new TestSpring());
     jf.setLocation(100,100);
     jf.setSize(400,280);
     jf.doLayout(); // Just for good measure...1
     jf.setVisible(true);
   }
}


---------- END SOURCE ----------

CUSTOMER WORKAROUND :
In the general case, none. For the specific case in the
source code, swap constraints A and B.
(Review ID: 160271) 
======================================================================

Comments
EVALUATION Unfortunately the setting of constraints is order dependant. The constraints object is used to determine two values along a given axis (left and right edge or top and bottom edge) but allows you to specify three Springs (west, width and east or north, height and south). If you have specified two of the springs along a give axis the other spring can be calculated. For example, if you specify the west and width spring, the east spring can be calculated as west + width. But what happens if both the west and width spring are specified (as is the default) and you specify an east spring? At this point the Constraints object is considered over constrained along a given axis and one of the edges must be reset. Why you ask? The values from the springs may not match, that is the value from the east spring may not match that of the west spring - width spring. The javadoc for Constraints indicates what happens when an axis is over constrained: Value Being Set(method used) - Result When Over-Constrained Horizontally (x, width, and the east edge are all non-null) ------------------------------------------ ------------------------------------------------------------------------------ x or the west edge (setX or setConstraint) width value is automatically set to east - x. width(setWidth) east edge's value is automatically set to x + width. east edge(setConstraint) x value is automatically set to east - width. The constraints object is first created such that the x edge has a spring bound to 0, and the width spring matches the prefered width. The example than sets the west edge. Everything is ok, as the horizontal axis is not over constrained. The example then sets the east constraint which results in the horizontal axis becoming over constrained and an edge must be reset. Looking at the above table shows the x edge will be reset to the east - width. Because the preferred width of an empty text field is almost 0, this results in a really small text field. The second test case is to reverse the order the edges are set in. If the east edge is set first the x edge will be reset, but the x edge will be again programmatically set to what is desired and everything works ok. ###@###.### 2002-08-05 I'm reopening this and moving it to RFE. Ideally setting the constraints would NOT be order dependent. ###@###.### 2005-2-11 00:57:51 GMT Phil has proposed a way to resolve this. The algorithm used to calculate springs will be based on the last two springs (along each axis) that have been specified. This fixs the problem in that SpringLayout will in effect know the last two springs that have been specified so that it doesn't have to guess at what you wanted and addresses the order previous order dependancy. For example, this bug was adding a component, specifying the west edge, then the east edge this resulted in the west edge getting reset to east - width. With the new code SpringLayout will remember the last two settings, in this case it will remember the developer specified the west edge, then east, resulting in deriving the width and all will work. The down side of this is that it has the potential for incompatability, in that if a developer was relying on the above algorithm, they would have problems. ###@###.### 2005-07-19 22:18:25 GMT
19-07-2005