具有输入验证的简单可编辑JTable

时间:2014-11-28 21:48:24

标签: java swing validation jtable tablecelleditor

我想写一个非常简单的JTable。

用户可以通过输入有效的双精度来编辑单元格。如果用户输入无效(即输入字符串),我希望我的表丢弃无效输入,显示最后一个好输入,并向用户显示错误消息。

我还希望表中的数字格式如下: " ### ##%"

我该怎么做呢?

其他信息
我知道我需要做的事情,但我在连接点时遇到了麻烦。

例如,我知道为了使格式正确,我必须继承DefaultTableCellRenderer但是我不确定我在getTableCellRendererComponent()方法中确切需要什么。

我很确定我必须继承DefaultCellEditor以使编辑和错误检查正常工作。虽然我已经阅读了很多不同的东西。我不确定检查有效输入的最佳位置。我还读过关于InputVerifier的信息,我不确定如何使用它,或者我是否应该使用它。

关于这样的事情如何起作用的一个小例子,以及我必须扩展/覆盖的不同类/方法的简要说明对我有用。

谢谢

1 个答案:

答案 0 :(得分:1)

  

我知道为了使格式正确,我必须继承DefaultTableCellRenderer但是我不确定我在getTableCellRendererComponent()方法中究竟需要什么。

请参阅Table Format Rendering以获取执行此操作的简便方法。此方法只是覆盖了渲染器的setValue(...)方法。

  

我很确定我必须继承DefaultCellEditor以使编辑和错误检查正常工作。

以下是我在论坛上找到的一些旧代码,它创建了一个自定义的IntegerEditor。第一列使用默认的Integer编辑器,第二列使用自定义编辑器。

import java.awt.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import javax.swing.text.*;
import java.text.*;
import java.awt.event.*;
public class TableIntegerEditor
{
    static class IntegerEditor extends DefaultCellEditor
    {
        JFormattedTextField ftf;
        NumberFormat integerFormat;
        private Integer minimum, maximum;
        private boolean DEBUG = false;

        public IntegerEditor(int min, int max)
        {
            super(new JFormattedTextField());

            setClickCountToStart(2);

            ftf = (JFormattedTextField)getComponent();
            ftf.setBorder(new LineBorder(Color.BLACK));
            minimum = new Integer(min);
            maximum = new Integer(max);

            //Set up the editor for the integer cells.
            integerFormat = NumberFormat.getIntegerInstance();
            NumberFormatter intFormatter = new NumberFormatter(integerFormat);
            intFormatter.setFormat(integerFormat);
            intFormatter.setMinimum(minimum);
            intFormatter.setMaximum(maximum);

            ftf.setFormatterFactory(new DefaultFormatterFactory(intFormatter));
            ftf.setValue(minimum);
            ftf.setHorizontalAlignment(JTextField.TRAILING);
            ftf.setFocusLostBehavior(JFormattedTextField.PERSIST);

            //React when the user presses Enter while the editor is
            //active.  (Tab is handled as specified by
            //JFormattedTextField's focusLostBehavior property.)
            ftf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "check");

            ftf.getActionMap().put("check", new AbstractAction()
            {
                public void actionPerformed(ActionEvent e)
                {
                    if (!ftf.isEditValid())  //The text is invalid.
                    {
                        if (userSaysRevert())
                        {
                            ftf.postActionEvent(); //inform the editor
                        }
                    }
                    else
                        try
                        {
                            ftf.commitEdit();     //so use it.
                            ftf.postActionEvent(); //stop editing
                        }
                        catch (java.text.ParseException exc) { }
                }
            });
        }

        @Override
        public boolean isCellEditable(EventObject event)
        {
            JTable table = (JTable)event.getSource();
            return true;
        }

        //Override to invoke setValue on the formatted text field.
        public Component getTableCellEditorComponent(
            JTable table, Object value, boolean isSelected, int row, int column)
        {
             JFormattedTextField ftf = (JFormattedTextField)super.getTableCellEditorComponent(
                table, value, isSelected, row, column);
             ftf.setValue(value);

             return ftf;
        }

        //Override to ensure that the value remains an Integer.
        public Object getCellEditorValue()
        {
            JFormattedTextField ftf = (JFormattedTextField)getComponent();
            Object o = ftf.getValue();
            if (o instanceof Integer)
            {
                return o;
            }
            else if (o instanceof Number)
            {
                return new Integer(((Number)o).intValue());
            }
            else
            {
                try
                {
                    return integerFormat.parseObject(o.toString());
                }
                catch (ParseException exc)
                {
                    System.err.println("getCellEditorValue: can't parse o: " + o);
                    return null;
                }
            }
        }

        //Override to check whether the edit is valid,
        //setting the value if it is and complaining if
        //it isn't.  If it's OK for the editor to go
        //away, we need to invoke the superclass's version
        //of this method so that everything gets cleaned up.
        public boolean stopCellEditing()
        {
            JFormattedTextField ftf = (JFormattedTextField)getComponent();

            if (ftf.isEditValid())
            {
                try
                {
                    ftf.commitEdit();
                }
                catch (java.text.ParseException exc) { }

            }
            else
            {
                if (!userSaysRevert())  //user wants to edit
                {
                    return false; //don't let the editor go away
                }
             }

             return super.stopCellEditing();
        }

        /**
         * Lets the user know that the text they entered is
         * bad. Returns true if the user elects to revert to
         * the last good value.  Otherwise, returns false,
         * indicating that the user wants to continue editing.
         */
        protected boolean userSaysRevert() {
             Toolkit.getDefaultToolkit().beep();
             ftf.selectAll();
             Object[] options = {"Edit",
                                        "Revert"};
             int answer = JOptionPane.showOptionDialog(
                  SwingUtilities.getWindowAncestor(ftf),
                  "The value must be an integer between "
                  + minimum + " and "
                  + maximum + ".\n"
                  + "You can either continue editing "
                  + "or revert to the last valid value.",
                  "Invalid Text Entered",
                  JOptionPane.YES_NO_OPTION,
                  JOptionPane.ERROR_MESSAGE,
                  null,
                  options,
                  options[1]);

             if (answer == 1) { //Revert!
                  ftf.setValue(ftf.getValue());
             return true;
             }
        return false;
        }


    }

    private static void createAndShowGUI()
    {
        String[] columnNames = {"String", "Integer", "Integer2"};
        Object[][] data =
        {
            {"a", new Integer(1), new Integer(10)},
            {"b", new Integer(2), new Integer(20)},
            {"c", new Integer(3), new Integer(30)}
        };

        JTable table = new JTable(data, columnNames)
        {
            public Class getColumnClass(int column)
            {
                if (column == 0)
                    return String.class;
                else
                    return Integer.class;
            }

        };
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane( table );

        table.getColumnModel().getColumn(2).setCellEditor( new IntegerEditor(0, 200) );

        DefaultCellEditor editor = (DefaultCellEditor)table.getDefaultEditor(Integer.class);
        JComponent border = (JComponent)editor.getComponent();
        border.setBorder( BorderFactory.createLineBorder( Color.RED ) );

        JFrame frame = new JFrame("Integer Editor");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( scrollPane );
        frame.setLocationByPlatform( true );
        frame.pack();
        frame.setVisible( true );
    }

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


}

如果您只想使用默认的Double编辑器,那么您只需要将列类更改为列的Double.class。如果您需要特殊编辑,那么您需要根据双重要求自定义IntegerEditor。