2

In my JTabbedPane, I am removing tabs in 2 different ways:

tabbedPane.remove(index)

and

tabbedPane.removeAll()

Both work fine in terms of closing the tabs. However, I have a change listener on my TabbedPane that calls back to another module to report on tab changes. This is where the problem is.

When adding and removing tabs using remove(index), the source TabbedPane in the stateChanged() method contains the correct number of tabs when checking tabbedPane.getTabCount().

However, when calling tabbedPane.getTabCount() after tabbedPane.removeAll(), the count is still the count that was present immediately before the removeAll().

Does anyone have any suggestions?

Lukas Rotter
  • 4,158
  • 1
  • 15
  • 35
thedude19
  • 2,643
  • 5
  • 34
  • 43

5 Answers5

10

After looking at the source code, I see what's happening.

JTabbedPane fires ChangeEvents when the selected tab is changed. But to remove all tabs, it first sets the selected tab to -1 and then removes all the tabs. So when the ChangeListener catches the event, all the tabs are still there.

If you want to know the number of tabs at all times, I'm afraid you'll have to iterate through the tabs yourself and remove them one by one.

while (myTabbedPane.getTabCount() > 0)
    myTabbedPane.remove(0);
Michael Myers
  • 188,989
  • 46
  • 291
  • 292
3

Here you go; use ContainerListener instead:

import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;

import javax.swing.JPanel;
import javax.swing.JTabbedPane;

import junit.framework.TestCase;

public class JTabbedPaneTest extends TestCase {
    private JTabbedPane pane;
    private int         count   = 0;

    protected void setUp() throws Exception {
        pane = new JTabbedPane();
        ContainerListener containerListener = new ContainerListener() {
            public void componentAdded(ContainerEvent e) {
                count++;
            }

            public void componentRemoved(ContainerEvent e) {
                count--;
            }
        };
        pane.addContainerListener(containerListener);
        JPanel panel1 = new JPanel();
        JPanel panel2 = new JPanel();
        pane.add(panel1);
        pane.add(panel2);
    }

    public void testOne() throws Exception {
        assertEquals(2, count);
        assertEquals(2, pane.getTabCount());
        pane.remove(0);
        pane.remove(0);
        assertEquals(0, count);
        assertEquals(0, pane.getTabCount());
    }

    public void testMany() throws Exception {
        assertEquals(2, count);
        assertEquals(2, pane.getTabCount());
        pane.removeAll();
        assertEquals(0, count);
        assertEquals(0, pane.getTabCount());
    }
}
Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
  • 2
    That might be better than mine, although it's a little hard to read in the middle of all that test code. – Michael Myers Jun 18 '09 at 16:40
  • This also makes sense. I guess since my question did mention ChangeListener, I should keep that one as the selected answer but still vote this one up? Or can there be multiple answers? Either way, thank you. – thedude19 Jun 18 '09 at 17:11
1

Try to call validate or revalidate

Pierre
  • 34,472
  • 31
  • 113
  • 192
0

Looking a the JTabbedPane code (version 6) both codes go through removeTabAt, which should decrease the count. It probably will fire off an event for each tab, however, meaning that the first event should have the getTabCount() one less then the count before the removeAll().

Are you certain about the getTabCount() call? What happens if you remove all tabs (from the end) manually?

Kathy Van Stone
  • 25,531
  • 3
  • 32
  • 40
0

Here's a test case that helps to expose the problem.

import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import junit.framework.TestCase;

public class JTabbedPaneTest extends TestCase {
    private JTabbedPane     pane;
    private int             count = 0;

    protected void setUp() throws Exception {
        pane = new JTabbedPane();
        ChangeListener listener = new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                JTabbedPane pane = (JTabbedPane)e.getSource();
                int before = count;
                count = pane.getTabCount();
                System.out.println(String.format("%s --> %s", before, count));
            }
        };
        pane.addChangeListener(listener);
        JPanel panel1 = new JPanel();
        JPanel panel2 = new JPanel();
        pane.add(panel1);
        pane.add(panel2);
    }

    public void testOne() throws Exception {
        assertEquals(1, count); // I actually expect 2
        assertEquals(2, pane.getTabCount());
        pane.remove(0);
        pane.remove(0);
        assertEquals(0, count);
        assertEquals(0, pane.getTabCount());
    }

    public void testMany() throws Exception {
        assertEquals(1, count); // I actually expect 2
        assertEquals(2, pane.getTabCount());
        pane.removeAll();
        assertEquals(2, count); // I actually expect 0
        assertEquals(0, pane.getTabCount());
    }
}

I think there is a synchronization issue going on; the output is:

0 --> 1
1 --> 1
1 --> 0
0 --> 1
1 --> 2

It looks as if some change events are being lost.

Update: leaving this in place for posterity, but it's wrong; as mmyers points out the events only fire when the selection changes.

Carl Manaster
  • 39,912
  • 17
  • 102
  • 155