Search code examples
javaswingjtablejcomboboxtablecelleditor

Changing Dropdown content in a JTable Column in Swing


I have a JTable in which the first column contains combobox with same items in each cell.If i select an item in a cell combobox i need to remove the selected item from all the other combobox in that column and also add the previous selected item to all the other combobox.How should i do that?Please help me with an example.

public class Save extends JFrame {
  String[] items1 = new String[] { "Cash", "Bank1", "Bank2" ,"Bank3"};
  TableCellEditor editors;
  DefaultTableModel dtmFunds;
  private JComboBox comboBox1;
  private JTable jtblFunds;

  private void loadTable(){
   comboBox1=new JComboBox(items1);
     comboBox1.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {

                    int x=comboBox1.getSelectedIndex();
                    comboItem= e.getItem().toString();
                }
            }
        }); 
     editors=new DefaultCellEditor(comboBox1);

    dtmFunds = new DefaultTableModel(new Object[][] {{"", " ","delete"}}, new Object[] {"Fund Store", "Amount","Action"});  
    jtblFunds=new JTable(dtmFunds){
        public TableCellEditor getCellEditor(int row,int column){

            int modelColumn=convertColumnIndexToModel(column);
            if(modelColumn==0 && row<jtblFunds.getRowCount()-1)
                return editors;
            else
                return super.getCellEditor(row,column);
        }
    };
    jtblFunds.setModel(dtmFunds);
    jtblFunds.getModel().addTableModelListener(new TableModelListener() {
        @Override
        public void tableChanged(TableModelEvent e) {                   
            int row=e.getFirstRow();
            int column=e.getColumn();
            if((column==0)&&(row<jtblFunds.getRowCount()-1)){
               System.out.println("Dropdown changed  "+row);
           }

        }
    });

  }
  }

These are are codes i have used to add combobox to JTable column named "Fund Store".


Solution

  • Really, focus your efforts within the CellEditor itself, that's it's job. There is no need to extend from JTable or screw around with it.

    import java.awt.Component;
    import java.awt.EventQueue;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.AbstractCellEditor;
    import javax.swing.DefaultComboBoxModel;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.table.DefaultTableModel;
    import javax.swing.table.TableCellEditor;
    
    public class TestCellEditor {
    
        public static void main(String[] args) {
            new TestCellEditor();
        }
    
        public TestCellEditor() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    List<String> values = new ArrayList<>(5);
                    values.add("Bananas");
                    values.add("Apples");
                    values.add("Oranages");
                    values.add("Grapes");
                    values.add("Pears");
    
                    ComboBoxTableCellEditor editor = new ComboBoxTableCellEditor(values);
                    DefaultTableModel model = new  DefaultTableModel(new Object[]{"Fruit"}, 5);
                    JTable table = new JTable(model);
                    table.getColumnModel().getColumn(0).setCellEditor(editor);
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new JScrollPane(table));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class ComboBoxTableCellEditor extends AbstractCellEditor implements TableCellEditor {
    
            private JComboBox editor;
            private List<String> masterValues;
    
            public ComboBoxTableCellEditor(List<String> masterValues) {
                this.editor = new JComboBox();
                this.masterValues = masterValues;
            }
    
            @Override
            public Object getCellEditorValue() {
                return editor.getSelectedItem();
            }
    
            @Override
            public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
    
                DefaultComboBoxModel model = new DefaultComboBoxModel(masterValues.toArray(new String[masterValues.size()]));
                for (int index = 0; index < table.getRowCount(); index++) {
                    if (index != row) {
                        String cellValue = (String) table.getValueAt(index, 0);
                        model.removeElement(cellValue);
                    }
                }
    
                editor.setModel(model);
                editor.setSelectedItem(value);
    
                return editor;
    
            }
        }
    
    }
    

    I'd prefer to have to two pools of values, one which is the master list and one which is the selected values, it would be easier and faster to prepare the editor each time it's invoked, but this is the basic idea...