【问题标题】:Java Swing Combobox removeAllItems calling ItemStateChanged also?Java Swing Combobox removeAllItems 也调用 ItemStateChanged?
【发布时间】:2012-04-29 11:17:50
【问题描述】:

我的代码实际上很简单。我看到一个简单相似的代码来自this article

起初,我有 1 个组合框。我有一个名为 itemStateChanged() 的监听器。我添加到这个监听器的目的是: "当用户从 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");
        }

    }

在代码后面,我抓取了一些数据,然后调用了 removeAllItems() 方法。 然后我在其中设置了一个新模型(来自新数据)。

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

当我执行 removeAllItem() 方法时,我意识到我的 itemStateChanged() 被调用。调用一次。

那么,如何让它只在用户单击(选择)时才被调用,而不是在 removeAllItems() 调用时调用?

它类似于this article. 但它不是removingItems 的情况。 CMIIW。

【问题讨论】:

  • 只需在 if (ie.getStateChange() == ItemEvent.SELECTED){} 中编写代码,因此当您调用 removeAllItem() 时,此块将不会运行。
  • @nIcEcOw:我已经这样做了,请看一下我刚刚在那里写的上面的代码......但有趣的情况是它正在运行,即使我已经使用了 ItemEvent.SELECTED if-else . :(
  • 我也测试过那个东西,就我而言,它不是那样做的,使用 JRE 1.7 update 3,不要放其他部分,因为你在问题中描述的,你只想要一种情况可以工作,所以只要部分可以。
  • OMG... 可能是因为我使用的是 JDK 1.6 更新 31

标签: java swing methods jcombobox comboboxmodel


【解决方案1】:

一种快速的方法是在调用 removeAllItem() 之前将 bool 设置为 true,然后再返回 false。仅当 bool 变量为 false 时才执行 itemStateChanged() 中的代码。

理想情况下,您可以覆盖 removeAllItem() 函数。

【讨论】:

  • 听起来像是一种奇怪的方法来解决可能是由他使用的ComboBoxModel 引起的问题。请参阅我对我认为正在发生的事情的回答,以及 nIcE cOw 的帖子,它表明它应该只适用于问题中发布的代码
  • 是的,这有点奇怪,但仍然可以用作替代方案。 :D
【解决方案2】:

在这里检查这段代码,它完美无缺,可能是你在调用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();
            }
        });
    }
}

【讨论】:

  • 在我的完整源代码中,实际上我是在 Thread 中进行的,是的。 JFrame 之外的一个线程调用该 Combobox。这有什么不同吗,@nice cOw?
  • 某种形式的SSCCE,对于提供一些可靠的答案会很有帮助,因为预测事情可能会导致更多的混乱:(
  • @gumuruh 你不应该在非 EDT 线程上修改 Swing 组件。有关更多信息,请参阅Concurrency in Swing 教程
  • 我不应该?但是,直到现在我正在使用我所有的 5-10 线程来修改我的 SWING 组件并且仍然可以正常运行。我的意思是,它真的使 Swing 死锁还是什么?好的,我会阅读该链接。 :D @Robin
  • @gumuruh 它可能会抛出异常,导致奇怪的可视化,死锁,......所有你真的不想要的东西
【解决方案3】:

正如 nIcE cOw 已经在他的示例中说明的那样,当您使用 DefaultComboBoxModel 时它肯定可以工作(在他的示例代码中就是这种情况,尽管它发生在屏幕后面)。

我可以解释您在非DefaultComboBoxModel 情况下遇到的行为,尽管您的代码 sn-p 建议您使用一种。查看JComboBox#removeAllItems 的源代码有不同的代码路径,因为removeAllElements 方法不是MutableComboBoxModel 接口的一部分

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

因此,对于非DefaultComboBoxModel,您将一一删除项目。这意味着在某个时间点,您将删除选定的元素。您的模型的可能实现可能会在此时更改所选元素。例如,如果您查看 DefaultComboBoxModel 中的实现(尽管不会触发此代码),您可以清楚地看到它改变了选择。

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

也许您的模型做了类似的事情,从而解释了该事件。只是为了使这篇文章完整,DefaultComboBoxModel#removeAllElements 后面的代码可以清楚地看到它将选择设置为null,并且不选择另一个对象。该代码中唯一奇怪的是它不会首先触发DESELECTED 事件,尽管您知道如果您侦听intervalRemoved 事件,则选择已更改......但这与您的问题并不真正相关

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

所以总结一下:我说你的问题的解决方案位于你的模型中,而不是你发布的代码中

【讨论】:

  • 这就是我所说的完整答案:-),在各个方面都清理了许多事情并提供了一些有价值的信息。
  • ic, ic, ic, @Robin... 这听起来很完整! :D 但是,如果用户不使用 setModel() 怎么办?相反,用户只做 removeAllItems() 然后 addItem(object), addItem(Object)... 它也执行 itemStateChanged() 你不觉得吗? :D
  • @gumuruh,这取决于您的型号。在这种情况下,DefaultComboBoxModel 会为第一个元素触发一个事件。看看那个方法的源码就知道了
【解决方案4】:

从整个讨论中不清楚,

  • 您必须在删除所有项目之前从 JComboBox 中删除所有侦听器,删除项目后您可以重新添加侦听器,

  • 仍然不确定是否要动态添加和删除项目,或者您可以为另一个 JComponent 设置任何值,

  • (反对把简单的事情复杂化)你看到那里删除了吗,

.

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

【讨论】:

  • 在从JComboBox 中删除项目之前删除所有Listeners 的良好解决方案:-)
  • 删除所有听众??我以前从未尝试过。如果我不@mKorbel,是否会导致内存量表满载?但我没有看到任何写“removeListener”的代码......你刚刚说删除监听器不是吗? ?:(
  • @gumuruh hehehe,请确保我们看不到您的代码的其余部分(整个):-),然后附加的侦听器之间可能存在一些无限循环,从上面的讨论来看,没有人知道: -)
【解决方案5】:

removeAllItems方法并没有调用ItemStateChanged,而是调用了actionPerformed,你可以通过运行这个简单的代码来检查:

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

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-29
    相关资源
    最近更新 更多