JDK-4835327 : componentShown only received for first doc in MDI
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.1,6
  • Priority: P4
  • Status: Resolved
  • Resolution: Cannot Reproduce
  • OS: generic,windows_nt
  • CPU: generic,x86
  • Submitted: 2003-03-20
  • Updated: 2014-04-07
  • Resolved: 2014-04-07
Related Reports
Relates :  
Description
Name: gm110360			Date: 03/20/2003


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

FULL OPERATING SYSTEM VERSION :
Windows NT version 4.0 SP6

ADDITIONAL OPERATING SYSTEMS :
RedHat Linux 7.2 (2.4.7 kernel)

A DESCRIPTION OF THE PROBLEM :
The componentShown method of the ComponentListener interface as
implemented by java.awt.Component does not get invoked in an MDI
application if a document is already visible.  After the first document
(frame) is created and added to the container (desktop), subsequent
frames do not receive the componentShown callback.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run the sample code below
2. Click on the empty desktop (application
frame) once.  This will create a new frame and add it to the desktop.  The
program will output a message to the console when the componentShown and
componentResized messages are received.  Once the frame has been created
and added to the desktop, the program will output "---" to indicate that the
process is complete (easier readability).
3. Click on the desktop
again.  This will create another new frame and add it to the desktop.  Since
the program creates only one type of internal frame, the console output
should be the same for all.



EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected:
The componentShown callback should be received every time a
new internal frame is added to the desktop.

Actual:
After the first
frame is created, subsequent new frames that are added to the desktop do
not receive the componentShown callback.

The display of the custom
panel "MyPanel" (which is listening for the componentShown callback) is
implemented as per the JDK documentation.  Namely, the internal frame
that holds a MyPanel (BaseInternalFrame)
calls:
setVisible(false);
setVisible(true);
on MyPanel after
creating it.

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class
TestFrame extends JFrame
{
	JDesktopPane desktop = null;

	public TestFrame()
	{
		// Setup application as MDI
		desktop = new JDesktopPane();
		setContentPane(desktop);

		// Make dragging faster:
		desktop.setDoubleBuffered(true);
		desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);	//1.3+ code

		// Use mouse "click" to spawn a new internal frame
		desktop.addMouseListener(new MouseAdapter()
		{
			public void mouseClicked(MouseEvent e)
			{
				createFrame();
				System.out.println("---");
			}
		} );

	}

	protected void createFrame()
	{
		BaseInternalFrame frame = null;

		frame = new BaseInternalFrame();
		frame.setVisible(false);
		frame.setVisible(true);					//necessary as of kestrel
		frame.setSize(200,200);
		desktop.add(frame);

		try
		{
			frame.setSelected(true);
		}
		catch (java.beans.PropertyVetoException e) { ; }
	}

	public static void main(String[] args)
	{
		JFrame f = new TestFrame();
		f.setBounds(100, 100, 300, 300);
		f.setVisible(true);
	}
}

class BaseInternalFrame extends JInternalFrame
{
	public static int InternalFrameCount = 0;

	public BaseInternalFrame()
	{
		super("Sample Internal Frame",
				true,				//resizable
				true,				//closable
				true,				//maximizable
				true);			//iconifiable

		CreateGUI();			//Create the GUI and put it in the window...
		pack();					// Then set the window size or call pack...

		setLocation(20 * InternalFrameCount, 20 * InternalFrameCount);
		setDoubleBuffered(true);

		InternalFrameCount++;
	}

	protected void CreateGUI()
	{
		JComponent c = (JComponent)getContentPane();

		c.setLayout(new BorderLayout() );

		JPanel p = new MyPanel();
		c.add(p,BorderLayout.CENTER);

		p.setVisible(false);
		p.setVisible(true);
	}

}

class MyPanel extends JPanel
{
	public MyPanel()
	{
		setLayout(new BorderLayout());
		JLabel l = new JLabel("A label.");
		add(l,BorderLayout.CENTER);

		addComponentListener(new ComponentAdapter()
		{
			public void componentResized(ComponentEvent e)
			{
				System.out.println("[ MyPanel ] resized");
			}

			public void componentShown(ComponentEvent e)
			{
				System.out.println("[ MyPanel ] shown");
			}
		} );
	}
}

---------- END SOURCE ----------
(Review ID: 146053) 
======================================================================

Comments
EVALUATION The last message in the forum says the bug appears to be fixed. Verify this in dolphin.
13-06-2006

EVALUATION Contribution-Forum:https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?messageID=11782&forumID=1463
03-03-2006

EVALUATION Name: osR10079 Date: 03/21/2003 The cause of the problem is as follows: every time when Component.setVisible(true) is called on non-visible component AWT makes it visible and post ComponentEvent (COMPONENT_SHOWN) for this component through EventQueue.postEvent(). But after that the test makes new internal frame selected, and this call results in a call to JLayeredPane.setLayer() which in turn removes some components with MyPanel instance for which we've post COMPONENT_SHOWN. And so we destroy peer for this panel and removes all events targeted on it from EventQueue. Thus after all MyPanel instances don't receive COMPONENT_SHOWN. Here is a part of call stack: at java.awt.Container.remove(Container.java:769) at javax.swing.JLayeredPane.setLayer(JLayeredPane.java:344) at javax.swing.JLayeredPane.setPosition(JLayeredPane.java:430) at javax.swing.JLayeredPane.moveToFront(JLayeredPane.java:401) at javax.swing.JInternalFrame.moveToFront(JInternalFrame.java:1133) at javax.swing.DefaultDesktopManager.activateFrame(DefaultDesktopManager.java:236) at javax.swing.plaf.basic.BasicInternalFrameUI.activateFrame(BasicInternalFrameUI.java:675) at javax.swing.plaf.basic.BasicInternalFrameUI$InternalFramePropertyChangeListener.propertyChange(BasicInternalFrameUI.java:451) at javax.swing.event.SwingPropertyChangeSupport.firePropertyChange(SwingPropertyChangeSupport.java:264) at javax.swing.event.SwingPropertyChangeSupport.firePropertyChange(SwingPropertyChangeSupport.java:232) at javax.swing.JComponent.firePropertyChange(JComponent.java:3822) at javax.swing.JInternalFrame.setSelected(JInternalFrame.java:1055) As far as i undersatand Swing does that to change z-order of components in some container and as soon as Swing will be able to do this without destroying component's peer the problem will be resolved. So I think we should be able to fix this bug after rfe 4533021 (Container needs API to change Z-ordering of children) will be implemented. But, definitely this is Swing's problem, so i recategorize it to Swing team. ###@###.###, March 21, 2003. ====================================================================== Yes, this bug sounds like it will be fixed with the new z-order work being done. Once that is implemented I will re-evaluate this bug. ###@###.### 2003-03-21
21-03-2003