Как пометить ввод ячейки JTable как недопустимый?

если я JTable и укажите тип класса столбца в его модели следующим образом:

   DefaultTableModel model = new DefaultTableModel(columnNames, 100) {
       @Override
        public Class<?> getColumnClass(int columnIndex) {
            return Integer.class;
        }};

затем, когда пользователь пытается ввести double значение в таблицу, Swing автоматически отклоняет вход и устанавливает контур ячейки в красный цвет.

Я хочу, чтобы тот же эффект произошел, когда кто-то вводит "отрицательный или 0" вход в ячейку. У меня есть вот что:

    @Override
    public void setValueAt(Object val, int rowIndex, int columnIndex) {
       if (val instanceof Number && ((Number) val).doubleValue() > 0) {
              super.setValueAt(val, rowIndex, columnIndex);
            } 
       }
   }

это предотвращает ячейку от принятия любых неположительных значений, но не устанавливает покрасьте в красный цвет и оставьте ячейку редактируемой.

Я попытался посмотреть, как JTable делает отказ по умолчанию, но я не могу его найти.

как я могу заставить его отклонить непозитивный вход так же, как он отклоняет нецелочисленный вход?

спасибо

3 ответов


на private static class JTable.GenericEditor использует интроспекцию, чтобы поймать исключения, вызванные конкретными строительства Number подклассы с поврежденных String значения. Если вам не нужно такое общее поведение, подумайте о создании PositiveIntegerCellEditor как подкласс DefaultCellEditor. Ваш stopCellEditing() метод был бы соответственно проще.

добавление: обновлено для использования RIGHT выравнивание и общий код ошибки.

добавление: см. также использование редактора для проверки Введенный Пользователем Текст.

enter image description here

    private static class PositiveIntegerCellEditor extends DefaultCellEditor {

    private static final Border red = new LineBorder(Color.red);
    private static final Border black = new LineBorder(Color.black);
    private JTextField textField;

    public PositiveIntegerCellEditor(JTextField textField) {
        super(textField);
        this.textField = textField;
        this.textField.setHorizontalAlignment(JTextField.RIGHT);
    }

    @Override
    public boolean stopCellEditing() {
        try {
            int v = Integer.valueOf(textField.getText());
            if (v < 0) {
                throw new NumberFormatException();
            }
        } catch (NumberFormatException e) {
            textField.setBorder(red);
            return false;
        }
        return super.stopCellEditing();
    }

    @Override
    public Component getTableCellEditorComponent(JTable table,
        Object value, boolean isSelected, int row, int column) {
        textField.setBorder(black);
        return super.getTableCellEditorComponent(
            table, value, isSelected, row, column);
    }
}

я понял. Переопределите DefaultCellEditor и верните false / установите границу в красный цвет, если заданное число не является положительным.

к сожалению, начиная с JTable.GenericEditor составляет static w/default объем, я не могу переопределить GenericEditor чтобы обеспечить эту функциональность и повторно реализовать ее с несколькими настройками, если у кого-то нет лучшего способа сделать это, что я хотел бы услышать.

    @SuppressWarnings("serial")
    class PositiveNumericCellEditor extends DefaultCellEditor {

        Class[] argTypes = new Class[]{String.class};
        java.lang.reflect.Constructor constructor;
        Object value;

        public PositiveNumericCellEditor() {
            super(new JTextField());
            getComponent().setName("Table.editor");
            ((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
        }

        public boolean stopCellEditing() {
            String s = (String)super.getCellEditorValue();
            if ("".equals(s)) {
                if (constructor.getDeclaringClass() == String.class) {
                    value = s;
                }
                super.stopCellEditing();
            }

            try {
                value = constructor.newInstance(new Object[]{s});
                if (value instanceof Number && ((Number) value).doubleValue() > 0)
                {
                    return super.stopCellEditing();
                } else {
                    throw new RuntimeException("Input must be a positive number."); 
                }
            }
            catch (Exception e) {
                ((JComponent)getComponent()).setBorder(new LineBorder(Color.red));
                return false;
            }
        }

        public Component getTableCellEditorComponent(JTable table, Object value,
                                                 boolean isSelected,
                                                 int row, int column) {
            this.value = null;
            ((JComponent)getComponent()).setBorder(new LineBorder(Color.black));
            try {
                Class type = table.getColumnClass(column);
                if (type == Object.class) {
                    type = String.class;
                }
                constructor = type.getConstructor(argTypes);
            }
            catch (Exception e) {
                return null;
            }
            return super.getTableCellEditorComponent(table, value, isSelected, row, column);
        }

        public Object getCellEditorValue() {
            return value;
        }
    }

этот код является небольшим улучшением принятого ответа. Если пользователь не вводит никакого значения, щелчок по другой ячейке должен позвольте ему выбрать другую ячейку. Принятое решение не допустить этого.

@Override
public boolean stopCellEditing() {

    String text = field.getText();

    if ("".equals(text)) {
        return super.stopCellEditing();
    }

    try {
        int v = Integer.valueOf(text);

        if (v < 0) {
            throw new NumberFormatException();
        }            
    } catch (NumberFormatException e) {

        field.setBorder(redBorder);
        return false;
    }

    return super.stopCellEditing();
}

это решение проверяет наличие пустого текста. В случае пустого текста, мы называем stopCellEditing() метод.