문제

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);
}
}
도움이 되었습니까?

해결책

  • 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();
        }
    }
}

다른 팁

i expected it to accept only number values

In general there is no need to create a custom editor. Just override the getColumnClass() method of the TableModel to return the proper class of data stored in model and the table will use appropriate renderer and editor.

However, if you want an editor to limit decimal places or do range checking on the number then you can use a custom editor.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top