Why is itemStateChanged on JComboBox is called twi

2019-01-09 05:15发布

问题:

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

回答1:

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



回答2:

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".



回答3:

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();
                }
            }
        });


回答4:

Yo can do it like this:

import java.awt.event.*;

jComboBox1.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Hello");
        }
    });


回答5:

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!



回答6:

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);
    }
}


回答7:

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.



回答8:

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."



回答9:

  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)]


回答10:

JComboBox.setFocusable(false) will do the trick.