Search code examples
javaswingjtabbedpane

JTabbedPane.getComponentAt() seems to return wrong component when tab is inserted using insertTab()


I encountered a strange problem with JTabbedPane when I try to insert a tab between other tabs. The UI is rendered as expected, but getComponentAt() returns a wrong component.

In my application, the user should have to possibility to rearrange tabs in any order he wants. To do this, I insert tabs using the insertTab() method. When doing this, tabs disappear and the remaining tabs have wrong content.

import java.awt.Component;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTabbedPane;

public class InsertTabExample extends JFrame {

    public InsertTabExample() {
        final JTabbedPane pane = new JTabbedPane();

        addTabsInReverseOrder(pane);
        dumpTabs(pane);

        add(pane);

        this.setSize(640, 480);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    private void addTabsInReverseOrder(final JTabbedPane pane) {
        for(int i = 0; i < 10; i++) {
            final String tabLabel = String.format("tab #%d", i);
            final String componentLabel = String.format("component #%d", i);

            final JLabel component = new JLabel(componentLabel);
            component.setName(componentLabel);

            pane.insertTab(tabLabel, null, component, null, 0);
        }
    }

    private void dumpTabs(final JTabbedPane pane) {

        for(int i = 0; i < pane.getTabCount(); i++) {
            final String tabName = pane.getTitleAt(i);
            final Component component = pane.getComponent(i);

            final int componentIndex = pane.indexOfComponent(component);

            System.out.println(String.format("Index %d -> tab '%s' -> component '%s' -> component index %d", i, tabName, component.getName(), componentIndex));
        }
    }

    public static void main(String[] args) {
        new InsertTabExample();
    }
}

As expected, the UI shows the tabs in reverse order (starting with "tab #9") and it also shows the correct component to each tab.

The output on the console shows something different. I expected to get


    Index 0 -> tab 'tab #9' -> component 'component #9' -> component index 9
    Index 1 -> tab 'tab #8' -> component 'component #8' -> component index 8
    Index 2 -> tab 'tab #7' -> component 'component #7' -> component index 7
    Index 3 -> tab 'tab #6' -> component 'component #6' -> component index 6
    Index 4 -> tab 'tab #5' -> component 'component #5' -> component index 5
    Index 5 -> tab 'tab #4' -> component 'component #4' -> component index 4
    Index 6 -> tab 'tab #3' -> component 'component #3' -> component index 3
    Index 7 -> tab 'tab #2' -> component 'component #2' -> component index 2
    Index 8 -> tab 'tab #1' -> component 'component #1' -> component index 1
    Index 9 -> tab 'tab #0' -> component 'component #0' -> component index 0

but what I get is


    Index 0 -> tab 'tab #9' -> component 'component #0' -> component index 9
    Index 1 -> tab 'tab #8' -> component 'component #1' -> component index 8
    Index 2 -> tab 'tab #7' -> component 'component #2' -> component index 7
    Index 3 -> tab 'tab #6' -> component 'component #3' -> component index 6
    Index 4 -> tab 'tab #5' -> component 'component #4' -> component index 5
    Index 5 -> tab 'tab #4' -> component 'component #5' -> component index 4
    Index 6 -> tab 'tab #3' -> component 'component #6' -> component index 3
    Index 7 -> tab 'tab #2' -> component 'component #7' -> component index 2
    Index 8 -> tab 'tab #1' -> component 'component #8' -> component index 1
    Index 9 -> tab 'tab #0' -> component 'component #9' -> component index 0

The tab labels are returned in expected order, but the components are listed in reverse order.

What's going wrong here? How do I correctly get the component of a specific tab?

Thanks for any hint!


Solution

  • TabbedPane keeps indexes in order from 0 to getTabCount() - so last tab couldn't be 0 - so when you add tabs put proper index: getTabCount()-i

     private void addTabsInReverseOrder(final JTabbedPane pane) {
        for(int i = 0; i < 10; i++) {
            final String tabLabel = String.format("tab #%d", i);
            final String componentLabel = String.format("component #%d", i);
    
            final JLabel component = new JLabel(componentLabel);
            component.setName(componentLabel);
    
            pane.insertTab(tabLabel, null, component, null, pane.getTabCount()-i);
        }
    }
    
    private void dumpTabs(final JTabbedPane pane) {
    
        for(int i = 0; i < pane.getTabCount(); i++) {
            final String tabName = pane.getTitleAt(i);
            final Component component = pane.getComponentAt(i);
    
            final int componentIndex = pane.indexOfComponent(component);
    
            System.out.println(String.format("Index %d -> tab '%s' -> component '%s' -> component index %d", i, tabName, component.getName(), componentIndex));
        }
    }
    

    Another mistake - pane.getComponent(i) gets the nth component in this container. And you need to replace with pane.getComponentAt(i) which returns the component at specific index.

    Output will be:

    Index 0 -> tab 'tab #9' -> component 'component #9' -> component index 0
    Index 1 -> tab 'tab #8' -> component 'component #8' -> component index 1
    Index 2 -> tab 'tab #7' -> component 'component #7' -> component index 2
    Index 3 -> tab 'tab #6' -> component 'component #6' -> component index 3
    Index 4 -> tab 'tab #5' -> component 'component #5' -> component index 4
    Index 5 -> tab 'tab #4' -> component 'component #4' -> component index 5
    Index 6 -> tab 'tab #3' -> component 'component #3' -> component index 6
    Index 7 -> tab 'tab #2' -> component 'component #2' -> component index 7
    Index 8 -> tab 'tab #1' -> component 'component #1' -> component index 8
    Index 9 -> tab 'tab #0' -> component 'component #0' -> component index 9
    

    So the index of the tab and component will not be in reverse order - it starts from 0 to getTabsCount().