How to avoid firing actionlistener event of JComboBox when an item is get added into it dynamically in java?

后端 未结 9 2255
广开言路
广开言路 2020-12-04 00:23

I need your suggestions and guidence on following task.

I have a frame which has two JComboBoxes supposed they are named combo1 and combo2, a JTable and other compon

相关标签:
9条回答
  • 2020-12-04 00:23

    This 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 can't just override setSelectedItem(...) or setSelectedIndex(...) because these are also used internally when items are actually selected by user keyboard or mouse actions, when you do not want to inhibit firing the listeners.

    0 讨论(0)
  • 2020-12-04 00:30

    I kind of went the stupid simple route with this issue for my program since I am new to programming.

    I changed the action listeners to have a counter if statement:

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

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

    topActionlistenersFromFiringOnLoad += 1;

    0 讨论(0)
  • 2020-12-04 00:32

    although its late, a better alternative would be to disabled the combobox to be modified prior to being modified. by doing so, you prevent firing events of the modified combobox, when for example, you use methods likes removeAllItems() or 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);
    
                }
            }
        });
    
    0 讨论(0)
  • 2020-12-04 00:35

    What i do instead of adding and removing action listeners i have a boolean variable in my action listeners that is true if it has to allow the action through or false if it has to block it.

    I then set it to false when i do some changes that will fire off the action listener

    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.
    
    0 讨论(0)
  • 2020-12-04 00:40

    The cleaner way is to use lambda expressions like this:

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

    For the above to work, you need the following method defined somewhere:

    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);
        }
    }
    
    0 讨论(0)
  • 2020-12-04 00:44

    To determine whether or not to perform various methods in actionListener interface methods (actionPerformed() blocks of code) use setActionCommand() on source components (combo1 or combo2).

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

    Here's a compilable example that uses this principle to have one combo set another combo's selected index while also displaying a String in a JTextField. By using setActionCommand() and guarding the comboActionPerformed() block of code, the JTextField will cycle through each word in the wordBank. If the comboActionPerformed() method was not guarded or if the actionCommand String was not changed, 2 actionEvents will trigger and the textField will skip 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's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
    
    }
    
    0 讨论(0)
提交回复
热议问题