Why is itemStateChanged on JComboBox is called twice when changed?
Asked Answered
B

10

41

I'm using a JComboBox with an ItemListener on it. When the value is changed, the itemStateChanged event is called twice. The first call, the ItemEvent is showing the original item selected. On the second time, it is showing the item that has been just selected by the user. Here's some tester code:

public Tester(){

    JComboBox box = new JComboBox();
    box.addItem("One");
    box.addItem("Two");
    box.addItem("Three");
    box.addItem("Four");

    box.addItemListener(new ItemListener(){
        public void itemStateChanged(ItemEvent e){
            System.out.println(e.getItem());
        }
    });

    JFrame frame = new JFrame();
    frame.getContentPane().add(box);
    frame.pack();
    frame.setVisible(true);
}

So when I changed the Combo box once from "One" to "Three" the console shows:

One
Three

Is there a way I can tell using the ItemEvent maybe, that it's the second item (ie. the user selected item)? And if someone can explain why it gets called twice, that would be nice too!

Thanks

Blais answered 1/12, 2008 at 11:40 Comment(0)
H
32

Have a look at this source:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Tester {

    public Tester(){

        JComboBox box = new JComboBox();
        box.addItem("One");
        box.addItem("Two");
        box.addItem("Three");
        box.addItem("Four");

        box.addItemListener(new ItemListener(){
            public void itemStateChanged(ItemEvent e){
                System.out.println(e.getItem() + " " + e.getStateChange() );
            }
        });

        JFrame frame = new JFrame();
        frame.getContentPane().add(box);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String [] args) {
        Tester tester = new Tester();
    }
}

Use the getStateChange to determine if an item is selected or deselected

Height answered 1/12, 2008 at 11:50 Comment(1)
It's generally good practice to ignore the event and look to see what the actual state is.Lettered
W
22

According to this thread,

It gets tripped when you leave one result and then called again when set to another result

Don't listen for itemStateChanged. Use an ActionListener instead, which is good for handling events of the combo.
You need a ItemStateListener if you need to separately handle deselection / selection depending on the item involved.

Changing the state of the item within itemStateChanged causes itemStateChanged to be fired... this called "reentrance".

Wafd answered 1/12, 2008 at 11:55 Comment(2)
you may also take note, that if : We do removeAll() method from a ComboBox the result is that it will also calling twice....Cimex
Note that if the user selects the same value as previously selected, an ActionListener will still be fired which doesn’t happen with an ItemListener.Horney
C
19

I wanted to get the index string after selected and set in combobox

        comboBox1.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if(e.getStateChange() == ItemEvent.SELECTED) {
                    comboBox1ItemStateChanged();
                }
            }
        });
Carbide answered 8/1, 2012 at 23:57 Comment(0)
H
7

Yo can do it like this:

import java.awt.event.*;

jComboBox1.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Hello");
        }
    });
Heehaw answered 22/7, 2009 at 19:9 Comment(1)
is actionperformed() is better than itemStateChanged() ?Cimex
L
7
private void dropDown_nameItemStateChanged(java.awt.event.ItemEvent evt) {                                                 


    if(evt.getStateChange() == ItemEvent.SELECTED)
    {
        String item = (String) evt.getItem();
        System.out.println(item);
    }

}

Good Luck!

Lockage answered 12/12, 2013 at 6:15 Comment(0)
L
3

The code is:

public class Tester {

    private JComboBox box;

    public Tester() {

        box = new JComboBox();
        box.addItem("One");
        box.addItem("Two");
        box.addItem("Three");
        box.addItem("Four");

        box.addItemListener(new ItemListener() {

            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == 1) {

                    JOptionPane.showMessageDialog(box, e.getItem());
                    System.out.println(e.getItem());
                }
            }
        });

        JFrame frame = new JFrame();
        frame.getContentPane().add(box);
        frame.pack();
        frame.setVisible(true);
    }
}
Linders answered 13/5, 2011 at 11:49 Comment(0)
B
3

Have a look here,

box.addItemListener(new ItemListener(){
    public void itemStateChanged(ItemEvent e){
        if(e.getStateChange()== ItemEvent.SELECTED) {
            //this will trigger once only when actually the state is changed
            JOptionPane.showMessageDialog(null, "Changed");
        }
    }
});

When you select a new option, it will only once call the JOptionPane, indicating that the code there will be called once only.

Bentinck answered 31/5, 2017 at 8:51 Comment(1)
It's better to use ItemEvent.SELECTED instead of 1Neddie
R
1

Quote from Java Tutorial:

"Only one item at a time can be selected in a combo box, so when the user makes a new selection the previously selected item becomes unselected. Thus two item events are fired each time the user selects a different item from the menu. If the user chooses the same item, no item events are fired."

Rheta answered 26/3, 2015 at 11:17 Comment(0)
H
0
  1. When the anyitem is selected from the combo box, it internally triggers selection change, i.e. it will call the function setSelectedItem.
  2. If an explicit itemStateChanged event listener is implemented, the setSelectedItem will call itemStateChanged. So, when an item is selected it calls setSelectedItem then it calls itemStateChanged.
  3. As the value of the combo box changes, even that too triggers itemStateChanged and hence itemStateChanged gets called.
  4. I had written listener for item change to handle change in value of combo box when set internally from the code and that caused the function getting called twice.

Here are the 2 back traces, which gets invoked when a value is selected from combo box.

1st time on actual value change:

dataMgr.MainInterface.jComboBoxPaymentStatusValueChangeHandle(MainInterface.java:1431), 
dataMgr.MainInterface.jComboBoxPaymentStatusItemStateChanged(MainInterface.java:1676), 
dataMgr.MainInterface.access$600(MainInterface.java:28), 
dataMgr.MainInterface$7.itemStateChanged(MainInterface.java:437), 
javax.swing.JComboBox.fireItemStateChanged(JComboBox.java:1223), 
javax.swing.JComboBox.selectedItemChanged(JComboBox.java:1271), 
javax.swing.JComboBox.contentsChanged(JComboBox.java:1330), 
javax.swing.AbstractListModel.fireContentsChanged(AbstractListModel.java:118), 
javax.swing.DefaultComboBoxModel.setSelectedItem(DefaultComboBoxModel.java:93), 
javax.swing.JComboBox.setSelectedItem(JComboBox.java:576), javax.swing.JComboBox.setSelectedIndex(JComboBox.java:622), javax.swing.plaf.basic.BasicComboPopup$Handler.mouseReleased(BasicComboPopup.java:852), java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:290), java.awt.Component.processMouseEvent(Component.java:6533), javax.swing.JComponent.processMouseEvent(JComponent.java:3324), javax.swing.plaf.basic.BasicComboPopup$1.processMouseEvent(BasicComboPopup.java:501), java.awt.Component.processEvent(Component.java:6298), java.awt.Container.processEvent(Container.java:2236), java.awt.Component.dispatchEventImpl(Component.java:4889), java.awt.Container.dispatchEventImpl(Container.java:2294), java.awt.Component.dispatchEvent(Component.java:4711), java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888), java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525), java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466), java.awt.Container.dispatchEventImpl(Container.java:2280), java.awt.Window.dispatchEventImpl(Window.java:2746), java.awt.Component.dispatchEvent(Component.java:4711), java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758), java.awt.EventQueue.access$500(EventQueue.java:97), java.awt.EventQueue$3.run(EventQueue.java:709), java.awt.EventQueue$3.run(EventQueue.java:703), java.security.AccessController.doPrivileged(Native Method), java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76), java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86), java.awt.EventQueue$4.run(EventQueue.java:731), java.awt.EventQueue$4.run(EventQueue.java:729), java.security.AccessController.doPrivileged(Native Method), java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76), java.awt.EventQueue.dispatchEvent(EventQueue.java:728), java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201), java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116), java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105), java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101), java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93), java.awt.EventDispatchThread.run(EventDispatchThread.java:82)]

2nd time from the due to operation on combobox

dataMgr.MainInterface.jComboBoxPaymentStatusValueChangeHandle(MainInterface.java:1431), 
dataMgr.MainInterface.jComboBoxPaymentStatusItemStateChanged(MainInterface.java:1676), 
dataMgr.MainInterface.access$600(MainInterface.java:28), 
dataMgr.MainInterface$7.itemStateChanged(MainInterface.java:437), 
javax.swing.JComboBox.fireItemStateChanged(JComboBox.java:1223), 
javax.swing.JComboBox.selectedItemChanged(JComboBox.java:1280), 
javax.swing.JComboBox.contentsChanged(JComboBox.java:1330), 
javax.swing.AbstractListModel.fireContentsChanged(AbstractListModel.java:118), 
javax.swing.DefaultComboBoxModel.setSelectedItem(DefaultComboBoxModel.java:93), 
javax.swing.JComboBox.setSelectedItem(JComboBox.java:576), 
javax.swing.JComboBox.setSelectedIndex(JComboBox.java:622), 
javax.swing.plaf.basic.BasicComboPopup$Handler.mouseReleased(BasicComboPopup.java:852), 
java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:290), 
java.awt.Component.processMouseEvent(Component.java:6533), 
javax.swing.JComponent.processMouseEvent(JComponent.java:3324), 
javax.swing.plaf.basic.BasicComboPopup$1.processMouseEvent(BasicComboPopup.java:501), 
java.awt.Component.processEvent(Component.java:6298), java.awt.Container.processEvent(Container.java:2236), 
java.awt.Component.dispatchEventImpl(Component.java:4889), java.awt.Container.dispatchEventImpl(Container.java:2294), 
java.awt.Component.dispatchEvent(Component.java:4711), java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888), 
java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525), java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466), 
java.awt.Container.dispatchEventImpl(Container.java:2280), java.awt.Window.dispatchEventImpl(Window.java:2746), 
java.awt.Component.dispatchEvent(Component.java:4711), java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758),
java.awt.EventQueue.access$500(EventQueue.java:97), java.awt.EventQueue$3.run(EventQueue.java:709), 
java.awt.EventQueue$3.run(EventQueue.java:703), java.security.AccessController.doPrivileged(Native Method),
java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76), 
java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86), 
java.awt.EventQueue$4.run(EventQueue.java:731), java.awt.EventQueue$4.run(EventQueue.java:729), 
java.security.AccessController.doPrivileged(Native Method), java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76), java.awt.EventQueue.dispatchEvent(EventQueue.java:728), java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201), java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116), java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105), java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101), java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93), java.awt.EventDispatchThread.run(EventDispatchThread.java:82)]
Hostel answered 23/12, 2016 at 3:39 Comment(0)
F
-4

JComboBox.setFocusable(false) will do the trick.

Finished answered 22/12, 2010 at 7:37 Comment(1)
this is not answering the question. IT still getting the same result: two event occured.Cimex

© 2022 - 2024 — McMap. All rights reserved.