简体   繁体   中英

ActionPerformed being called when JComboBox is clicked in Jtable cell

I am using JComboBox in Jtable cell. When I click on the JComboBox and select a value from it, it calls the ActionPerformed fuction. Till here it is working fine but as soon as I click on the JComboBox again, it calls the ActionPerformed function, which it should not. What I want is, to call the ActionPerformed function when the item is selected in the JComboBox . In other words it should work as it worked for the first time when the item was selected from the JComboBox and then the ActionPerformed function was called. I cannot figure out why this problem is occurring. Here are the links that I have looked into and I did some other searches also but still could not find any relative answer to the above mentioned problem.

  1. Adding JComboBox to a JTable cell
  2. How to use ActionListener on a ComboBox to give a variable a value
  3. https://coderanch.com/t/339842/java/ComboBox-ItemListener-calling

Here is the code, you can copy paste it and check it.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableColumn;

public class TableExample implements ActionListener{

    JFrame frame;
    JComboBox skuNameComboBoxTable;

    TableExample() {
        frame = new JFrame();
        String data[][] = {{"101", "Amit", "Choose"},
        {"102", "Jai", "Choose"},
        {"101", "Sachin", "Choose"}};
        String column[] = {"ID", "Name", "Degree"};
        JTable table = new JTable(data, column);
        table.setBounds(30, 40, 200, 300);
        JScrollPane scrollPane = new JScrollPane(table);
        frame.add(scrollPane);
        frame.setSize(300, 400);
        frame.setVisible(true);

        String[] array = {"BS(SE)", "BS(CS)", "BS(IT)"};
        skuNameComboBoxTable = new JComboBox(array);
        skuNameComboBoxTable.addActionListener(this);

        TableColumn col = table.getColumnModel().getColumn(2);
        col.setCellEditor(new DefaultCellEditor(skuNameComboBoxTable));
    }

    public static void main(String[] args) {
        new TableExample();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        JOptionPane.showMessageDialog(null, "actionPerformed called");
    }
}

Kindly tell me why this problem is occurring and how should I solve it.

You can try using ItemListener and filter your action according to the ItemEvent.

import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.JComboBox;
import javax.swing.JFrame;


public class JComboBoxTest {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        String[] items = {"One", "Two", "Three"};
        JComboBox cb = new JComboBox(items);
        cb.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    System.out.println("Selected " + e.getItem());
                } else {
                    System.out.println("Deselected " + e.getItem());
                }
            }
        });

        frame.add(cb);

        frame.pack();
        frame.setVisible(true);
    }
}

Unfortunately, you can't do much when using the DefaultCellEditor - that is how it behaves. Within your code you can add a check to ensure that a change in value occured before handling the event. Something like below:

public void actionPerformed(ActionEvent e) {
    if (skuNameSelected == null || skuNameComboBoxTable.getSelectedItem() != skuNameSelected)
        JOptionPane.showMessageDialog(null, "actionPerformed called: ");
    skuNameSelected = (String) skuNameComboBoxTable.getSelectedItem();
}

This is happening because you are using the same JComboBox as the DefaultCellEditor for column 2.

Whenever you click a cell from column 2 the ComboBox will change to the value that is on the cell at the moment and that triggers the DESELECT (from the old value) and the SELECT (for the new value). This will only happen if the old value and the new value are not the same .

One way to avoid this is to add a CellEditorListener on the DefaultCellEditor that you are using, like below:

TableColumn col = table.getColumnModel().getColumn(2);
DefaultCellEditor cellEditor = new DefaultCellEditor(skuNameComboBoxTable);
col.setCellEditor(cellEditor);

cellEditor.addCellEditorListener(new CellEditorListener() {

            @Override
            public void editingStopped(ChangeEvent e) {
                System.out.println("Value of combo box defined!");
            }

            @Override
            public void editingCanceled(ChangeEvent e) {
                System.out.println("Edition canceled, set the old value");
            }
});

This way you will be able to only act when the value has been defined by the ComboBox.

I hope this helps.

You should not be using an ActionListener for this. The combo box uses its own ActionListener to update the TableModel when an item is selected.

So instead you should be listening for changes in the TableModel in order to do your custom code. So you should be using a TableModelListener to listen for changes in the data. However, a TableModelListener can fire an event even if just start and stop editing of the cell which might be a problem for you.

In this case you can use the Table Cell Listener . It will only generate an event when the value in the TableModel has changed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM