jtablejcomboboxitemlistener

JTable: JComboBox ItemListener triggered without change


I added a JComboBox to a JTable:

table.getColumnModel().getColumn(16).setCellEditor(new  DefaultCellEditor(c = new JComboBox()));
c.addItemListener(new CItemListener());

The Listener is fired when (de)selecting an Item. That's fine. My problem is however, that say: I've got "B" selected in one rows combobox, and "A" in another. When I have the combobox + row of "B" selected and now select the row with "A", the Listener is fired with Item "B" deselected and "A" selected, although I did not change the selection by itself. This is only true if I click on a combobox(without changing selection), not if I select the row somewhere else.

Can this behaviour be changed? If so: how?

Goal: Listener is only fired when a selection is made, not when the combobox is de/selected without changing an item.

Listener:

@Override
public void itemStateChanged(ItemEvent ie) {
    String s = "";

    if (ie.getStateChange() == ItemEvent.SELECTED){
        if (table.getSelectedRow() != -1){
            s = table.getModel().getValueAt(table.convertRowIndexToModel(table.getSelectedRow()), 1) );
            anotherTable.increaseCountFor(s);
            }
        } else if (ie.getStateChange() == ItemEvent.DESELECTED){
            if (table.getSelectedRow() != -1){
                s = table.getModel().getValueAt(table.convertRowIndexToModel(table.getSelectedRow()), 1) );
                anotherTable.decreaseCountFor(s);
            }
        }

Solution

  • Problems with your current approach

    As you are listening to itemStateChanged of Combobox it will be called for all rows even if one row is changed,as it is an expected behavior.[Try putting a print statement in that listener to see this]

    There is no need to listen to combobox change what you want to listen in column change of the table

    As you are incrementing based on some value of combobox values.I came up with the following solution.

    There is a mainTable in which 2nd column[index 1] is a dropdown. Whenever the combobox value changed for any row in mainTable the oldvalue is decremented and newvalue ins incremented in a counterTable.

    I have overridden the DefaultTableModel so that whenever the setValue is called it will check whether it is our desired column and if so it will do a decrement for old value and increment for new value in the counter table

    Just run the below SSCCE code and select values from second column and see the changes

    The following does what you've asked for

    import java.awt.BorderLayout;
    import java.util.Objects;
    import javax.swing.DefaultCellEditor;
    import javax.swing.DefaultComboBoxModel;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JTable;
    import javax.swing.table.DefaultTableModel;
    
    
    public class TableDropDown extends JFrame {
    
    private JComboBox jComboBox1;
    private JTable mainTable = new JTable();
    private JTable counterTable = new JTable();
    
    public TableDropDown() {
        initialize();
    }
    
    private void initialize() {
    
        //Loading the mainTable with sample values 
        DefaultTableModel model = new DefaultTableModel(new Object[][]{
            {"Test", null, null},
            {"Type", null, null},
            {"What", null, null},
            {"Which", null, null}
        },
                new String[]{
                    "Title 1", "Title 2", "Title 3"
                }) {
                    @Override
                    //Main part that does the trick
                    public void setValueAt(Object newValue, int row, int column) {
                        //check if this is our column
                        if (column == 1) {
                            Object oldvalue = getValueAt(row, column);
                            if (!Objects.equals(newValue, oldvalue)) {
                                if (oldvalue != null) {
                                    decreaseCountFor(oldvalue.toString());
                                }
                                increaseCountFor(newValue.toString());
                            }
                        }
                        super.setValueAt(newValue, row, column);
                    }
                };
    
        mainTable.setModel(model);
    
        //loading counterTable and combobox sample values A to J
        String[] contents = new String[10];
        DefaultTableModel cModel = new DefaultTableModel(null,
                new String[]{"Type", "Count"});
        for (int i = 0; i < 10; i++) {
            contents[i] = "" + (char) (i + 65);
            cModel.addRow(new Object[]{contents[i], 0});
        }
        counterTable.setModel(cModel);
        counterTable.setEnabled(false);//to disable editing
    
        jComboBox1 = new JComboBox(new DefaultComboBoxModel(contents));
    
        //setting cellEditor for Column 1
        mainTable.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(jComboBox1));
    
        //stuffs to add value to frame
        add(new javax.swing.JScrollPane(mainTable), BorderLayout.CENTER);
        add(new javax.swing.JScrollPane(counterTable), BorderLayout.EAST);
        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    
    public int getRowForValue(String val) {
        for (int i = 0; i < counterTable.getRowCount(); i++) {
            if (counterTable.getValueAt(i, 0).equals(val)) {
                return i;
            }
        }
        return -1;
    }
    
    public int getPrevoiusValue(int row) {
        return Integer.parseInt(counterTable.getValueAt(row, 1).toString());
    }
    
    public void increaseCountFor(String x) {
        int row = getRowForValue(x);
        counterTable.setValueAt(getPrevoiusValue(row) + 1, row, 1);
    }
    
    public void decreaseCountFor(String x) {
        int row = getRowForValue(x);
        counterTable.setValueAt(getPrevoiusValue(row) - 1, row, 1);
    }
    
    public static void main(String[] args) {
        new TableDropDown().setVisible(true);
    }
    }