javaswingjtabletablecelleditor

Custom table cell editor in java with column data type Float


As we know by default, we have to press Enter key twice to change selection while editing a cell in JTable.

To override this behaviour I am trying to write a custom table cell editor where upon single Enter key press, editing in current cell is finished, selection is changed to next row and editing is started in newly selected cell and its contents are automatically selected.

The whole scenario is working fine for integers BUT NOT FOR FLOAT DATA TYPE. for columns with data type Float/Double I get error

java.lang.IllegalArgumentException: Cannot format given Object as a Number

when Enter is pressed to change selection.

I am using following code, that I found while searching online.

package javaapplication1;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.AbstractCellEditor;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
import javax.swing.text.JTextComponent;

/**
 *
 * @author alqama
 */
public class test extends JPanel{
    
    private JTable table;
    
    test()
    {
        table = new JTable(){

        @Override
        public void changeSelection(    int row, int column, boolean toggle, boolean extend)
        {
            super.changeSelection(row, column, toggle, extend);

            if (editCellAt(row, column))
            {
                Component editor = getEditorComponent();
                editor.requestFocusInWindow();
                ((JTextComponent) editor).selectAll();

            }
        }};
        DefaultTableModel dtm = new javax.swing.table.DefaultTableModel(
                new Object [][] {

                    },
                new String [] { "Integer","Float"}
            ) {
                public Class getColumnClass(int col) {
                if(col==0) return java.lang.Integer.class;
                return java.lang.Float.class;
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return true;
            }
        };
        table.setModel(dtm);
        CustomTableCellEditor et = new CustomTableCellEditor(table);
        table.getColumnModel().getColumn(1).setCellEditor(et);
        table.getColumnModel().getColumn(0).setCellEditor(et);
        
        for (int i = 0; i < 5; i++) {
            dtm.addRow(new Object[]{i,1.5+i});
        }    
        
        
        table.setPreferredScrollableViewportSize(new Dimension(123, 123));
        this.add(new JScrollPane(table));
        
    }
    private void display() {
        JFrame f = new JFrame("Test Table");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new test().display();
            }
        });
    } 
    
    
    
    
    protected class CustomTableCellEditor  extends AbstractCellEditor implements TableCellEditor {
     
         private JTable table;
         JTextField component = new JTextField();

        public CustomTableCellEditor(JTable table) {
            this.table = table;
        }

        public boolean stopCellEditing() {
            
            boolean ans = super.stopCellEditing();            
            return ans;
        }

        @Override
        public void cancelCellEditing() {
            super.cancelCellEditing();
        }

        @Override
        public Object getCellEditorValue() {
            return component.getText();        
        }

        @Override
        public Component getTableCellEditorComponent(JTable arg0, Object value,
                boolean arg2, int arg3, int arg4) {
            component.setText(value.toString());
            return component;
        }
     }
}

Solution

  • You model's implementation of getColumnClass() for column 1 returns Float.class, so your implementation of getCellEditorValue() should return a value of the same type:

    @Override
    public Object getCellEditorValue() {
        return Float.valueOf(component.getText());        
    

    As an alternative, you can specify the editor by class:

    CustomTableCellEditor et = new CustomTableCellEditor(table);
    table.setDefaultEditor(Float.class, et);