using JTable cell editor

Mohamed Iqzas picture Mohamed Iqzas · Oct 31, 2013 · Viewed 7.4k times · Source

I am not sure why the editor i am setting for my jtable is not being called. I used the editor example from another SO Question.

When i edit my jtable it simply edits as string... i expected it to accept only number values. may be some exception if i type any other text... but i dont think the editor is being called here when i edit my table.

import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.NumberFormatter;

import java.awt.*;
import java.awt.event.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Locale;

public class Grow extends JFrame {

private static final Object[][] rowData = {{"Hello", "World"}};
private static final Object[] columnNames = {"A", "B"};

private JTable table;
private DefaultTableModel model;

public Grow() {
     Container c = getContentPane();
     c.setLayout(new BorderLayout());

     model = new DefaultTableModel(rowData, columnNames);
     table = new JTable();
     table.setModel(model);
     c.add(new JScrollPane(table), BorderLayout.CENTER);
     JButton add = new JButton("Add");
     JButton delete = new JButton("Delete");
     c.add(add, BorderLayout.LINE_START);
     add.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
             model.addRow(rowData[0]);
         }
     });

     table.setCellEditor(new NumberCellEditor());

     c.add(delete, BorderLayout.LINE_END);
     delete.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
             if(table.getSelectedRow()>-1)
                 model.removeRow(table.getSelectedRow());
         }
     });

     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     pack(); 
}

class NumberCellEditor extends DefaultCellEditor {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public NumberCellEditor(){
        super(new JFormattedTextField());
    }

    @Override
     public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        JFormattedTextField editor = (JFormattedTextField) super.getTableCellEditorComponent(table, value, isSelected, row, column);

        if (value!=null){
            DecimalFormat numberFormat = new DecimalFormat("#,##0.00;(#,##0.00)");
            editor.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(numberFormat)));
            Number num = (Number) value;  
            String text = numberFormat.format(num);
            editor.setHorizontalAlignment(SwingConstants.RIGHT);
            editor.setText(text);
        }
        System.out.println(value);
        return editor;
    }

    /*@Override
    public boolean stopCellEditing() {
        try {
            // try to get the value
            //this.getCellEditorValue();
            return super.stopCellEditing();
        } catch (Exception ex) {
            return false;
        }

    }
    */

    @Override
    public Object getCellEditorValue() {
        // get content of textField
        String str = (String) super.getCellEditorValue();
        if (str == null) {
            return null;
        }

        if (str.length() == 0) {
            return null;
        }

        // try to parse a number
        try {
            ParsePosition pos = new ParsePosition(0);
            Number n = NumberFormat.getInstance().parse(str, pos);
            if (pos.getIndex() != str.length()) {
                throw new ParseException(
                        "parsing incomplete", pos.getIndex());
            }

            // return an instance of column class
            return new Float(n.floatValue());

        } catch (ParseException pex) {
            throw new RuntimeException(pex);
        }
    }
    }

public static void main(String[] args) {
    Grow g = new Grow();
    g.setLocationRelativeTo(null);
    g.setVisible(true);
}
}

Answer

mKorbel picture mKorbel · Oct 31, 2013
  • use plain vanilla JTextField with DocumentFilter instead of JFormattedTextField as editors Component.

  • I cant comment something, attached start_point for JFormattedTextField with XxxFormat (important details are in offical Oracle tutorial, APIs How to use FormattedTextField, NumberFormat etc.)

  • you can to add InternationalFormatter for filtering only Numbers

e.g.

InternationalFormatter formatter = new InternationalFormatter(format);
formatter.setAllowsInvalid(false);
//formatter.setMinimum(0.0);
//formatter.setMaximum(1000.00);

screen_shot

enter image description here

from code

import java.awt.Component;
import java.awt.EventQueue;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import javax.swing.*;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;

public class EditorAsRendererTableTest {

    public EditorAsRendererTableTest() {
        JTable table = new JTable(3, 2);
        TableColumnModel colModel = table.getColumnModel();
        colModel.getColumn(0).setCellEditor(new MyCellEditor());
        colModel.getColumn(0).setCellRenderer(new MyCellEditor());
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        frame.add(new JScrollPane(table));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new EditorAsRendererTableTest();
            }
        });
    }

    private class MyCellEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {

        private static final long serialVersionUID = 1L;
        private JFormattedTextField renderer;
        private JFormattedTextField editor;
        private NumberFormat format = DecimalFormat.getInstance();

        public MyCellEditor() {
            format.setMinimumFractionDigits(2);
            format.setMaximumFractionDigits(4);
            format.setRoundingMode(RoundingMode.HALF_UP);
            renderer = new JFormattedTextField(format);
            renderer.setBorder(null);
            editor = new JFormattedTextField(format);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            renderer.setValue(value);
            return renderer;
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            editor.setValue(value);
            return editor;
        }

        @Override
        public boolean stopCellEditing() {
            try {
                editor.commitEdit();
            } catch (ParseException e) {
                return false;
            }
            return super.stopCellEditing();
        }

        @Override
        public Object getCellEditorValue() {
            return editor.getValue();
        }
    }
}