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

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

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

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

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

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

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

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

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

您可以在添加新元素之前删除动作侦听器,并在完成后将其添加回来。 Swing是单线程的,因此无需担心需要触发侦听器的其他线程。

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

我做了什么而不是添加和删除动作侦听器我在我的动作侦听器中有一个布尔变量,如果必须允许动作通过则为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. 

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

 String orderByOptions[] = {"smallest","highest","longest"}; JComboBox jcomboBox_orderByOption1 = new JComboBox jcomboBox_orderByOption2 = new JComboBox jcomboBox_orderByOption3 = new JComboBox 

更干净的方法是使用这样的lambda表达式:

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

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

 public static void do(final JComboBox 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); } } 

这有效:

 /** 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(...)因为当您不想禁止触发侦听器时,这些内容也会在用户键盘或鼠标操作实际选择项目时在内部使用。

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

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

这是一个可编译的示例,它使用此原则使一个组合设置另一个组合的选定索引,同时还在JTextField中显示一个String。 通过使用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 candyCombo; JComboBox 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(); } }); } } 

尝试这个:

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

因为我是编程新手,所以我为这个程序找到了这个问题的愚蠢简单路径。

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

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

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

topActionlistenersFromFiringOnLoad += 1;