How to avoid JComboBox action actionener event when an element is added dynamically to it in java?

I need your suggestions and recommendations for the next assignment.

I have a frame that has two JComboBoxes, which are supposedly called combo1 and combo2, JTable and other components.

At the initial stage, when the frame is visible with the above component. The combo1 combination is filled with some values, but at the initial stage no value is selected, combobo combobox is disabled and the table is empty.

I added actionListener to combo1 as well as combo2. There are two types of values ​​in combo1: suppose these values ​​are type1 and type2.

Condition 1: When we select the type1 value from Combo1, the actionListener method is called combo1, which calls the method that combo2 remains disabled, and adds some rows to the table associated with the selected type1 value from combo1.

Condition 2: when we select the type2 value from combo1, the actionListener method is called combo1, which calls the method that causes combo2 to fill in with some values ​​of type 2 and is turned on, but the value is not selected from combo2, and the table should also remain empty until we will not select any value from combo2.

each time a value is added to combo2, the combo2 action listener method is launched. In the actionListener method is combo2, which receives the value combo2, but there is no combo2 value selected, which throws a NullPointerException.

So, what should I do so that the combo2 member list method does not execute after adding values ​​to combo2.

+4
source share
8 answers

You can remove the action listener before adding new elements and add it back after completion. Swing has a single-threaded thread, so there is no need to worry about other threads requiring a listener.

Perhaps your listener can also check if something is selected and take appropriate action if not. Better than getting NPE.

+10
source

What I do instead of adding and removing action listeners, I have a boolean variable in my action handlers that is true if it should allow the action through or false if it should block it.

Then I set it to false when I make some changes that the action listener will reset

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. 
+5
source

although it’s too late, a better alternative would be to disable the drop-down field, which must be changed before its modification. thereby you prevent overtaking events of the modified combobox when, for example, you use methods like removeAllItems () or addItem ()

p>

 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); } } }); 
+2
source

A cleaner way is to use lambda expressions as follows:

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

In order for the above to work, you need the following method:

 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); } } 
+2
source

It works:

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

Note. You cannot just override setSelectedItem(...) or setSelectedIndex(...) , because they are also used internally when elements are actually selected using the user's keyboard or mouse actions, when you do not want to prevent listeners from starting.

+1
source

To determine whether to execute various methods in the methods of the ActionListener interface (actionPerformed () code blocks), use setActionCommand () for the source components (combo1 or combo2).

In your example, before adding elements to combo2, call setActionCommand ("doNothing") and protect your comboBoxActionPerformed () method.

Here's a compiled example that uses this principle to have one combo set another combined index, also displaying String in a JTextField. Using setActionCommand () and protecting the comboActionPerformed () code block, JTextField will loop through each word in the wordBank. If the comboActionPerformed () method has not been protected or if the actionCommand String has not been changed, 2 actionEvents are activated, and the text element skips words.

 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 GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } } 
0
source

try the following:

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

I kind of went a stupid easy way with this problem for my program, since I'm new to programming.

I changed the action listeners to have an if counter:

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

Then at the end of creating the java program, I added 1 to the counter:

topActionlistenersFromFiringOnLoad += 1;

-1
source

Source: https://habr.com/ru/post/1343160/


All Articles