Changing Dropdown content in a JTable Column in Swing

2.6k views Asked by At

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".

2

There are 2 answers

5
MadProgrammer On BEST ANSWER

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...

3
StanislavL On

All you need in fact is to update model of the comboBox you use for the editor.

comboBox1.setModel(new DefaultComboBoxModel(theArrayWithRemovedValue));

You have base array of combobox items (source) and result array of items where the selected one should be removed.

Just recreate the array removing value of the cell.

BTW. It's better to define cell editor standard way rather than overriding getCellEditor() method of JTable. Use e.g. public void setDefaultEditor(Class<?> columnClass, TableCellEditor editor). You can define a custom class for the column 0.