Java Swing Combobox removeAllItems calling ItemStateChanged also?

血红的双手。 提交于 2019-12-30 11:05:25

问题


My code is quite simple actually. I saw a simple and similar code was from this article.

At first, I have 1 combobox. I have a listener on it called itemStateChanged(). My purpose to add into this listener is that; "to execute some code when user click (select) an item from its dropbox".

Cmb_ItemCategory = new javax.swing.JComboBox();

Cmb_ItemCategory.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Loading..." }));

Cmb_ItemCategory.addItemListener(new java.awt.event.ItemListener() {
    public void itemStateChanged(java.awt.event.ItemEvent evt) {
        Cmb_ItemCategoryItemStateChanged(evt);
    }
});

private void Cmb_ItemCategoryItemStateChanged(java.awt.event.ItemEvent evt) {

        if(evt.getStateChange() == java.awt.event.ItemEvent.SELECTED){
        System.err.println("Sombody click or change my model content");
        }

    }

Behind the code, I grab some data, and then calling a method of removeAllItems() . And then I set a new Model (from new data) into it.

-- at another line of code ---
Cmb_ItemCategory.removeAllItems();
Cmb_ItemCategory.setModel(newModel);

I juz realized that my itemStateChanged() is called when i do the removeAllItem() method. called once.

So, How to make it only called once user Click (select) only AND not when removeAllItems() called?

it similar to this article. But it's not removingItems case. CMIIW.


回答1:


As nIcE cOw already illustrated in his example, it should certainly work when you use a DefaultComboBoxModel (which is the case in his sample code, although it happens behind the screens).

I could explain the behavior you encounter for the non-DefaultComboBoxModel case, although your code snippet suggests you use one. Looking at the source code for JComboBox#removeAllItems there is a different code path since the removeAllElements method is not part of the MutableComboBoxModel interface

public void removeAllItems() {
    checkMutableComboBoxModel();
    MutableComboBoxModel<E> model = (MutableComboBoxModel<E>)dataModel;
    int size = model.getSize();

    if ( model instanceof DefaultComboBoxModel ) {
        ((DefaultComboBoxModel)model).removeAllElements();
    }
    else {
        for ( int i = 0; i < size; ++i ) {
            E element = model.getElementAt( 0 );
            model.removeElement( element );
        }
    }
    selectedItemReminder = null;
    if (isEditable()) {
        editor.setItem(null);
    }
}

So with a non-DefaultComboBoxModel you are going to remove the items one by one. This means that at a certain point in time, you will remove the selected element. A possible implementation of your model might change the selected element at that point. If you look for example at the implementation in DefaultComboBoxModel (although this code will not be triggered) you can clearly see it changes the selection.

public void removeElementAt(int index) {
    if ( getElementAt( index ) == selectedObject ) {
        if ( index == 0 ) {
            setSelectedItem( getSize() == 1 ? null : getElementAt( index + 1 ) );
        }
        else {
            setSelectedItem( getElementAt( index - 1 ) );
        }
    }

    objects.removeElementAt(index);

    fireIntervalRemoved(this, index, index);
}

Perhaps your model does something similar, which explains the event. Just for making this post complete, the code behind the DefaultComboBoxModel#removeAllElements where you can clearly see it sets the selection to null and does not select another object. Only weird thing in that code is that it does not fire a DESELECTED event first, although you know the selection has changed if you listen for the intervalRemoved event ... but that is not really relevant to your problem

public void removeAllElements() {
    if ( objects.size() > 0 ) {
        int firstIndex = 0;
        int lastIndex = objects.size() - 1;
        objects.removeAllElements();
        selectedObject = null;
        fireIntervalRemoved(this, firstIndex, lastIndex);
    } else {
        selectedObject = null;
    }
}

So to conclude: I say the solution for your problem is located in your model, and not in the code you posted




回答2:


Here check this code out, this works flawlessly, might be you doing something wrong where you calling removeAllItems() :

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

public class ComboState 
{
    private void createAndDisplayGUI()
    {
        JFrame frame = new JFrame("Combo State Testing : ");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        final JComboBox cbox = new JComboBox();
        cbox.addItem("One");
        cbox.addItem("Two");
        cbox.addItem("Three");
        cbox.addItem("Four");
        cbox.addItemListener(new ItemListener()
        {
            public void itemStateChanged(ItemEvent ie)
            {
                if (ie.getStateChange() == ItemEvent.SELECTED)
                {
                    System.out.println("Item Selected is : " + ie.getItem());
                }
                /*else
                {
                    System.out.println("I am called for other reasons.");
                }*/
            }
        });

        /*
         * Click me to remove JComboBox's items.
         */
        JButton removeButton = new JButton("REMOVE");
        removeButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                cbox.removeAllItems();
            }
        });

        frame.add(cbox, BorderLayout.CENTER);
        frame.add(removeButton, BorderLayout.PAGE_END);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new ComboState().createAndDisplayGUI();
            }
        });
    }
}



回答3:


One quick way to do is to have a bool set to true before you call removeAllItem() and back false after. Execute the code in your itemStateChanged() only if the bool variable is false.

Ideally you could override the removeAllItem() function.




回答4:


not clear from whole discusion,

  • you have to remove all Listener(s) from JComboBox before removing all Items, after Items are removed you can add Listener(s) back,

  • still not sure if you want to add & remove Items dynamically, or you can set whatever value for another JComponent(s),

  • (against complicating simple things) did you see there remove,

.

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

public class ComboBoxTwo extends JFrame implements ActionListener, ItemListener {

    private static final long serialVersionUID = 1L;
    private JComboBox mainComboBox;
    private JComboBox subComboBox;
    private Hashtable<Object, Object> subItems = new Hashtable<Object, Object>();

    public ComboBoxTwo() {
        String[] items = {"Select Item", "Color", "Shape", "Fruit"};
        mainComboBox = new JComboBox(items);
        mainComboBox.addActionListener(this);
        mainComboBox.addItemListener(this);
        //prevent action events from being fired when the up/down arrow keys are used
        //mainComboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
        getContentPane().add(mainComboBox, BorderLayout.WEST);
        subComboBox = new JComboBox();//  Create sub combo box with multiple models
        subComboBox.setPrototypeDisplayValue("XXXXXXXXXX"); // JDK1.4
        subComboBox.addItemListener(this);
        getContentPane().add(subComboBox, BorderLayout.EAST);
        String[] subItems1 = {"Select Color", "Red", "Blue", "Green"};
        subItems.put(items[1], subItems1);
        String[] subItems2 = {"Select Shape", "Circle", "Square", "Triangle"};
        subItems.put(items[2], subItems2);
        String[] subItems3 = {"Select Fruit", "Apple", "Orange", "Banana"};
        subItems.put(items[3], subItems3);
//      mainComboBox.setSelectedIndex(1);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String item = (String) mainComboBox.getSelectedItem();
        Object o = subItems.get(item);
        if (o == null) {
            subComboBox.setModel(new DefaultComboBoxModel());
        } else {
            subComboBox.setModel(new DefaultComboBoxModel((String[]) o));
        }
    }

    @Override
    public void itemStateChanged(ItemEvent e) {
        if (e.getStateChange() == ItemEvent.SELECTED) {
            if (e.getSource() == mainComboBox) {
                if (mainComboBox.getSelectedIndex() != 0) {
                    FirstDialog firstDialog = new FirstDialog(ComboBoxTwo.this,
                            mainComboBox.getSelectedItem().toString(), "Please wait,  Searching for ..... ");
                }
            } 
        }
    }

    private class FirstDialog extends JDialog {

        private static final long serialVersionUID = 1L;

        FirstDialog(final Frame parent, String winTitle, String msgString) {
            super(parent, winTitle);
            setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
            JLabel myLabel = new JLabel(msgString);
            JButton bNext = new JButton("Stop Processes");
            add(myLabel, BorderLayout.CENTER);
            add(bNext, BorderLayout.SOUTH);
            bNext.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent evt) {
                    setVisible(false);
                }
            });
            javax.swing.Timer t = new javax.swing.Timer(1000, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    setVisible(false);
                }
            });
            t.setRepeats(false);
            t.start();
            setLocationRelativeTo(parent);
            setSize(new Dimension(400, 100));
            setVisible(true);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new ComboBoxTwo();
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}



回答5:


The method removeAllItems does not call ItemStateChanged, but it call actionPerformed, you can check it by running this simple code:

public class Tuto {

    public static void main(String[] args) {
        //create the main frame
        JFrame frame = new JFrame();
        frame.setResizable(false);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLayout(null);
        frame.setLocation(new Point(10, 10));
        frame.setPreferredSize(new Dimension(400, 300));

        JComboBox<String> combo = new JComboBox();
        combo.addItem("item 1");
        combo.addItem("item 2");
        combo.addItem("item 3");
        combo.setBounds(50, 30, 300, 20);
        combo.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                System.out.println(" action Performed ");
            }
        });
        frame.add(combo);

        JButton button = new JButton("Remove");
        button.setBounds(50, 100, 100, 30);
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                combo.removeAllItems();
            }
        });
        frame.add(button);

        frame.pack();
        frame.setVisible(true);
    }

}


来源:https://stackoverflow.com/questions/10202718/java-swing-combobox-removeallitems-calling-itemstatechanged-also

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!