如何在java中动态添加项目时,如何避免触发JComboBox的actionlistener事件?

时间:2011-03-10 10:49:37

标签: java swing jcombobox actionlistener

我需要你对以下任务的建议和指导。

我有一个框架有两个JComboBox,假设它们被命名为combo1和combo2,一个JTable和其他组件。

在使用上述组件可见框架的初始阶段。 combo1组合框中填充了一些值,但在初始阶段没有选择任何值,combo2组合框被禁用,表格为空。

我在combo1和combo2上添加了一个actionListener。 combo1中有两种类型的值,假设这些值是type1和type2。

条件1:     当我们从Combo1中选择值type1时,将调用actionListener方法combo1,该方法调用combo2保持禁用的方法,并将一些行添加到与combo1中的选定值type1相关的表中。

条件2:     当我们从combo1中选择值type2时,将调用actionListener方法combo1,该方法调用一个方法,该方法使combo2填充了与type2相关的一些值并启用但是没有从combo2中选择任何值,并且在我们从中选择任何值之前,表也应保持为空combo2。

每次向combo2添加值时,表都会触发combo2的动作侦听器方法。在combo2的actionListener方法中,它获取了combo2选择的值,但是这里没有选择的combo2值导致NullPointerException。

那么我应该怎么做才能在将值添加到combo2后才能执行combo2的动作列表器方法。

9 个答案:

答案 0 :(得分:10)

您可以在添加新元素之前删除动作侦听器,并在完成后将其添加回来。 Swing是单线程的,所以不需要担心需要激活监听器的其他线程。

您的听众也可能会检查是否选择了某些内容,如果没有,则采取适当的措施。比获得NPE更好。

答案 1 :(得分:6)

我做的不是添加和删除动作侦听器我在动作侦听器中有一个布尔变量,如果必须允许动作通过则为true,如果必须阻止它则为false。

然后,当我执行一些将触发动作侦听器的更改时,我将其设置为false

JComboBox test = new JComboBox();
test.addActionListener(new ActionListener()
{
  @Override
  public void actionPerformed(ActionEvent e)
  {
    if(testActionListenerActive)
    {
      //runn your stuff here
    }
  }
});

//then when i want to update something where i want to ignore all action evetns:
testActionListenerActive = false;
//do stuff here like add 

SwingUtilities.invokeLater(() -> testActionListenerActive = false);
//and now it is back enabled again
//The reason behind the invoke later is so that if any event was popped onto the awt queue 
//it will not be processed and only events that where inserted after the enable 
//event will get processed.

答案 2 :(得分:2)

尽管已经很晚了,但更好的选择是在修改之前禁用要修改的组合框。通过这样做,可以防止修改组合框的触发事件,例如,您使用的方法如 removeAllItems() addItem()

String orderByOptions[] = {"smallest","highest","longest"};

JComboBox<String> jcomboBox_orderByOption1 = new JComboBox<String(orderByOptions);
JComboBox<String> jcomboBox_orderByOption2 = new JComboBox<String(orderByOptions);
JComboBox<String> jcomboBox_orderByOption3 = new JComboBox<String(orderByOptions);

jcomboBox_orderByOption1.addItemListener(new ItemListener()
{
    public void itemStateChanged(ItemEvent itemEvent)
    {
            int eventID = itemEvent.getStateChange();

            if (eventID == ItemEvent.SELECTED)
            {
                Object selectedItem = jcomboBox_orderByOption1.getSelectedItem();

                jcomboBox_orderByOption2.setEnabled(false);
                jcomboBox_orderByOption2.removeAllItems();

                for (String item: string_orderByOptions)
                {
                    if (!item.equals(selectedItem))
                    {
                        jcomboBox_orderByOption2.addItem(item);
                    }
                }

                jcomboBox_orderByOption2.setEnabled(true);
            }
        }
    });



    jcomboBox_orderByOption2.addItemListener(new ItemListener()
    {
        public void itemStateChanged(ItemEvent itemEvent)
        {
            int eventID = itemEvent.getStateChange();

            if (eventID == ItemEvent.SELECTED)
            {
                Object selectedItem1 = jcomboBox_orderByOption1.getSelectedItem();
                Object selectedItem2 = jcomboBox_orderByOption2.getSelectedItem();

                jcomboBox_orderByOption3.setEnabled(false);

                jcomboBox_orderByOption3.removeAllItems();

                for (String item: string_orderByOptions)
                {
                    if (!item.equals(selectedItem1) && !item.equals(selectedItem2))
                    {
                        jcomboBox_orderByOption3.addItem(item);
                    }
                }

                jcomboBox_orderByOption3.setEnabled(true);

            }
        }
    });

答案 3 :(得分:2)

更简洁的方法是使用这样的lambda表达式:

do(comboBox, () -> comboBox.setSelectedItem("Item Name"));

要使上述工作正常,您需要在某处定义以下方法:

public static void do(final JComboBox<String> component, final Runnable f) {
    final ActionListener[] actionListeners = component.getActionListeners();
    for (final ActionListener listener : actionListeners)
        component.removeActionListener(listener);
    try {
        f.run();
    } finally {
        for (final ActionListener listener : actionListeners)
            component.addActionListener(listener);
    }
}

答案 4 :(得分:1)

这有效:

/** Implements a Combo Box with special setters to set selected item or
  * index without firing action listener. */
public class MyComboBox extends JComboBox {

/** Constructs a ComboBox for the given array of items. */
public MyComboBox(String[] items) {
  super(items);
}

/** Flag indicating that item was set by program. */
private boolean isSetByProgram;

/** Do not fire if set by program. */
protected void fireActionEvent() {
  if (isSetByProgram)
    return;
  super.fireActionEvent();
}

/** Sets selected Object item without firing Action Event. */
public void setSelection(Object item) {
  isSetByProgram = true;
  setSelectedItem(item);
  isSetByProgram = false;
}

/** Sets selected index without firing Action Event. */
public void setSelection(int index) {
  isSetByProgram = true;
  setSelectedIndex(index);
  isSetByProgram = false;
}

}

注意:您无法覆盖setSelectedItem(...)setSelectedIndex(...),因为当您不想禁止触发时,当用户通过用户键盘或鼠标操作实际选择项目时,这些内容也会在内部使用听众。

答案 5 :(得分:1)

试试这个:

       indicatorComboBox = new JComboBox() {

        /**
         * Do not fire if set by program.
         */
        protected void fireActionEvent() {
            // if the mouse made the selection -> the comboBox has focus
            if(this.hasFocus())
                super.fireActionEvent();
        }
    };

答案 6 :(得分:0)

要确定是否在actionListener接口方法(actionPerformed()代码块)中执行各种方法,请对源组件(combo1或combo2)使用setActionCommand()。

对于您的示例,在向combo2添加元素之前,请调用setActionCommand(&#34; doNothing&#34;)并保护您的comboBoxActionPerformed()方法。

这是一个可编辑的示例,它使用此原则使一个组合设置另一个组合的选定索引,同时还在JTextField中显示一个字符串。通过使用setActionCommand()并保护comboActionPerformed()代码块,JTextField将循环遍历wordBank中的每个单词。如果没有保护comboActionPerformed()方法或者没有更改actionCommand String,则会触发2个actionEvents,textField将跳过单词。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

/** @author PianoKiddo */
public class CoolCombos extends JPanel {
    JComboBox<String> candyCombo;
    JComboBox<String> flavorCombo;
    JTextField field;
    String[] wordBank;
    int i = 0;

CoolCombos() {
    super();
    initComponents();
    addComponentsToPanel();
}

private void initComponents() {
    initCombos();
    initTextField();
}

private void initCombos() {
    ActionListener comboListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            comboActionPerformed(e);
        }
    }; 
    String[] candyList = {"Sourpatch", "Skittles"};
    String[] flavorList = {"Watermelon", "Original"};
    candyCombo = new JComboBox<>(candyList);
    candyCombo.addActionListener(comboListener);
    flavorCombo = new JComboBox<>(flavorList);
    flavorCombo.addActionListener(comboListener);
}

private void initTextField() {
    wordBank = new String[]{"Which", "Do", "You", "Like", "Better?"};
    field = new JTextField("xxxxx");
    field.setEditable(false);
    field.setText(wordBank[i]);
}

private void addComponentsToPanel() {
    this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
    this.add(candyCombo);
    this.add(flavorCombo);
    this.add(field);
}

public void comboActionPerformed(ActionEvent e) {
    String command = e.getActionCommand();
    if (!command.equals("doNothing")) {
        JComboBox combo = (JComboBox) e.getSource();
        if (combo.equals(candyCombo)) {
            setOtherComboIndex(candyCombo, flavorCombo); }
        else {
            setOtherComboIndex(flavorCombo, candyCombo); }
        displayText(); //replace here for toDo() code
    }
}

private void setOtherComboIndex(JComboBox combo, JComboBox otherCombo) {
    String command = otherCombo.getActionCommand();
    otherCombo.setActionCommand("doNothing"); //comment this line to skip words.
    otherCombo.setSelectedIndex(combo.getSelectedIndex());
    otherCombo.setActionCommand(command);
}

private void displayText() {
    i++; 
    String word;
    if (i > 4) { i = 0; }
    word = wordBank[i]; 
    field.setText(word);
    this.repaint();
}

/**
 * Create the GUI and show it.  For thread safety,
 * this method should be invoked from the
 * event-dispatching thread.
 */
private static void createAndShowGUI() {
    //Create and set up the window.
    JFrame frame = new JFrame("CoolCombos");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    //Create and set up the content pane.
    JComponent newContentPane = new CoolCombos();
    newContentPane.setOpaque(true); //content panes must be opaque
    frame.setContentPane(newContentPane);

    //Display the window.
    frame.pack();
    frame.setMinimumSize(frame.getSize());
    frame.setVisible(true);
}

public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
}

}

答案 7 :(得分:-1)

由于我是编程新手,因此我的程序出现了这个问题的愚蠢简单路径。

我将动作侦听器更改为具有计数器if语句:

if(stopActionlistenersFromFiringOnLoad != 0){//action performed ;}

然后在java程序创建结束时,我向计数器添加了1:

topActionlistenersFromFiringOnLoad += 1;

答案 8 :(得分:-1)

为避免addItem方法触发事件,最好在JComboBox中使用DefaultComboBoxModel来添加数据。另外,如果调用model.addElement(),则会触发一个事件,因此,您可以将所有元素添加到模型中,以后再使用JComboBox.setModel(model)。这样,如果您向模型中添加元素,则不会触发事件,因为尚未将JComboBox与模型链接。然后,我给你看一个例子。

public class MyClass
{

    private readonly ILoggerFactory _loggerFactory;


    public MyClass(ILoggerFactory loggerFactory)
    {
        _loggerFactory = _loggerFactory;
    }
    public void MyFunc()
    {
       new MyNewThatsASpecialCase(_loggerFactory.CreateLogger("MyNewThatsASpecialCase"));
    }
}

首先,我们创建模型,将所有元素添加到模型中(不会触发事件,因为您尚未将JComboBox与模型链接),我们使用ArrendatarioComboBox.setModel(model)将模型与JComboBox链接。链接后,事件被触发。