United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6285072 : JTabbedPane setSelectedIndex does not display correct component

Details
Type:
Bug
Submit Date:
2005-06-14
Status:
Resolved
Updated Date:
2010-04-02
Project Name:
JDK
Resolved Date:
2005-08-17
Component:
client-libs
OS:
windows_xp
Sub-Component:
javax.swing
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
5.0
Fixed Versions:

Related Reports
Relates:

Sub Tasks

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

<verified in all subsequent runtimes>

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

A DESCRIPTION OF THE PROBLEM :
When programmatically setting the selected index, the Tabbed Pane does not correctly set visiblity on its components within the tabs to allow the selected tab to be visible.  This is true even when selection code is executed within the dispatch thread.

@bug 4459110 appears to be similar to this report, but dismissed due to dispatch thread.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the included program.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The displayed component Should be Blue (The component at index 2)
ACTUAL -
The Displayed component is Green (the component at index 1)

By clicking on index 1, then index 2 again, the correct component is displayed

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;


/**
 *
 */
public class ITabControlTest
{

    public static void main(String[] args)
    {
        Runnable runner = new Runnable()
        {
            public void run()
            {
                JFrame frame = new JFrame();
                frame.setTitle("setSelectedIndex Bug");
                frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
                JTabbedPane foo = new JTabbedPane();
//                ITabControl foo = new ITabControl();
        
                JPanel a = buildComplex(Color.RED);
                JPanel b = buildComplex(Color.GREEN);
                JPanel c = buildComplex(Color.BLUE);
                foo.add(a, 0);
                foo.add(b, 1);
                foo.add(c, 2);
                
                frame.getContentPane().add(foo);
                frame.pack();
                frame.show();
                
                foo.setSelectedIndex(0);
                foo.setComponentAt(0,(Component)new JPanel());
                foo.setComponentAt(0, a);
        
                foo.setSelectedIndex(1);
                foo.setComponentAt(1,(Component)new JPanel());
                foo.setComponentAt(1, b);
        
                foo.setSelectedIndex(2);
                foo.setComponentAt(2,(Component)new JPanel());
                foo.setComponentAt(2, c);
        
                foo.setSelectedIndex(0);
                foo.setSelectedIndex(2);
            }
        };
        SwingUtilities.invokeLater(runner);
    }

    
    private static JPanel buildComplex(Color p_color)
    {
        JPanel pan = new JPanel();
        pan.setPreferredSize(new Dimension(300,300));
        pan.setBackground(p_color);
        return pan;
    }
}

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

CUSTOMER SUBMITTED WORKAROUND :
I am not sure this works around all facets of this bug, but:
in subclass of JTabbedPane:

public void setSelectedIndex()
{
        Component comp = getSelectedComponent();
        if(comp != null)
            comp.setVisible(false);

        super.setSelectedIndex(p_index);

}
###@###.### 2005-06-14 06:20:33 GMT

                                    

Comments
EVALUATION

The problem here lies with JTabbedPane.setComponentAt(). It immediately sets the new component to visible if the new component is being added at the selected index. The problem with this is that this new visible component doesn't stay in synch with BasicTabbedPaneUI which tracks the visible component and is responsible for making tab components invisible and visible when the tab changes. BasicTabbedPaneUI isn't updated until revalidate() is processed.

In this test case, the sequence of events causes three separate tabs to be made visible (via setTabComponentAt()) before the revalidates are processed. Once the revalidate() is processed, BasicTabbedPaneUI has a chance to update it's "visible component" component, making the old "visible component" invisible and the new one visible. The problem is that there are now multiple old components that are visible that BasicTabbedPaneUI doesn't know about.

The fix is simple - JTabbedPane.setComponentAt() should set the visibility based on the visibility of the component it is replacing. If it's replacing null, it will be set to invisible (and possibly set to visible if it should be later on during layout).
                                     
2005-07-29



Hardware and Software, Engineered to Work Together