JDK-6637796 : setBounds doesn't enlarge Component
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp,windows_vista
  • CPU: x86
  • Submitted: 2007-12-05
  • Updated: 2011-05-18
  • Resolved: 2011-05-18
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 7
7 b25Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b22)
Java HotSpot(TM) Client VM (build 11.0-b08, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
I tried to resize components for example: java.awt.TextField without success.

I set initial bounds of a TextField in a Panel with null Layout. Everything is ok. I tried to change bounds automatically and the component doesn't change the size.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
- Create an empty applet
- set null layout to applet container
- define textfield with bounds for example 10, 10, 50, 20
- add textfield to applet container
- show applet
- change bounds to 10, 10 , 2, 2 (through program logic)
- change bounds back to 10, 10, 50, 20 (through program logic)

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
painted textield with "visible" bounds 10, 10 , 50, 20
ACTUAL -
invalid repainted textfield

bounds are 10, 10 , 50, 20 but I don't see the textfield on screen, as expected.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package jdk.test;

import java.applet.Applet;
import java.awt.Button;
import java.awt.Rectangle;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * Simple setBounds and resize test
 *
 * @author JRx
 */
public class BugReportApplet extends Applet
                              implements ActionListener
{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Members
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	/** default username bounds */
	private static final Rectangle REC_USERNAME = new Rectangle(10, 10, 80, 20);

	/** input username */
	private TextField tfUsername;
	
	/** test button */
	private Button butResize;
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Override
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	@Override
	public void start()
	{
		
	}
	
	@Override
	public void stop()
	{
		
	}
	
	@Override
	public void init()
	{
		/* Username */
		
		tfUsername = new TextField(10);
		tfUsername.setBounds(BugReportApplet.REC_USERNAME);
		
		butResize = new Button("Resize");
		butResize.setBounds(10, 40, 50, 25);
		
		butResize.addActionListener(this);
		
		/* MAIN LAYOUT */
		
		setLayout(null);

		add(tfUsername);
		
		add(butResize);
	}
	
	@Override
	public void destroy()
	{
		
	}
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Interfaces
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	//ACTIONLISTENER
	
	public void actionPerformed(ActionEvent ae)
	{
		Rectangle rec = tfUsername.getBounds();

		
		if (rec.width < 10)
		{
			tfUsername.setBounds(BugReportApplet.REC_USERNAME);
		}
		else
		{
			tfUsername.setBounds(10, 10, 5, 5);
		}
	}
	
}	//BugReportApplet

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

Comments
EVALUATION We should slightly change the logic the mixing code uses to decide whether the current bounds of a component can be trusted. Previously we used the isValid() method, that actually deals with layouting, rather than with the correctness of the bounds. So, the solution is to introduce the new private method areBoundsValid() which produces the following result: 1. If the component does not have a container: we can trust the bounds. 2. If the component's container has null-layout: we can trust them also. 3. If the container is valid: we can trust them again. Finally, if the container is currently invalid, it means that it should relayout it self soon, which means that the bounds of its children cannot be trusted. In this case the areBoundsValid() method returns false.
05-02-2008

SUGGESTED FIX diff -r 37a05a11f281 src/share/classes/java/awt/Component.java --- a/src/share/classes/java/awt/Component.java Sat Dec 01 00:00:00 2007 +0000 +++ b/src/share/classes/java/awt/Component.java Tue Feb 05 16:30:54 2008 +0300 @@ -9452,6 +9452,19 @@ public abstract class Component implemen // ************************** MIXING CODE ******************************* + /** + * Check whether we can trust the current bounds of the component. + * The return value of false indicates that the container of the + * component is invalid, and therefore needs to be layed out, which would + * probably mean changing the bounds of its children. + * Null-layout of the container or absence of the container mean + * the bounds of the component are final and can be trusted. + */ + private boolean areBoundsValid() { + Container cont = getContainer(); + return cont == null || cont.isValid() || cont.getLayout() == null; + } + /** * Applies the shape to the component * @param shape Shape to be applied to the component @@ -9475,7 +9488,7 @@ public abstract class Component implemen // to modify the object outside of the mixing code. this.compoundShape = shape; - if (isValid()) { + if (areBoundsValid()) { Point compAbsolute = getLocationOnWindow(); if (mixingLog.isLoggable(Level.FINER)) { @@ -9602,7 +9615,7 @@ public abstract class Component implemen void applyCurrentShape() { checkTreeLock(); - if (!isValid()) { + if (!areBoundsValid()) { return; // Because applyCompoundShape() ignores such components anyway } if (mixingLog.isLoggable(Level.FINE)) {
05-02-2008

WORK AROUND If the validate() method is invoked right next to the setBounds() call, the component behaves as expected (correctly changing its bounds and its shape).
04-02-2008

EVALUATION The setBounds() method (actually, the reshape()) invalidates the component, and does not validate it back after changing the bounds. The mixing code gets invoked on every reshape to recalculate the current shape of the component, however this code ignores invalid components (because these may be incorrectly sized/located while they are invalid). So, after the first setBounds() the text field in the given test code becomes invalid, and the mixing code does not alter its shape on subsequent calls of the setBounds() method. To fix the bug we need to investigate the 'valid' property a bit further. One possible solution is to cause revalidating of the component after the setBounds() is invoked. But doing so in the reshape() method might cause some performance regressions. It might happen that the best solution would be manually invoking the validate() method after each setBounds() call.
04-02-2008

EVALUATION Not reproducible on Linux with JDK7 b13, b19-b21, at least with appletviewer. Reproducible on Windows since JDK7 b19.
05-12-2007

EVALUATION May be caused by the fix for 4811096.
05-12-2007