11

如果我采用 aJTable并在其模型上指定列的类类型,如下所示:

   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 是如何拒绝的,但我似乎找不到它。

我怎样才能让它拒绝非正输入,就像它拒绝非整数输入一样?

4

4 回答 4

15

使用自省来捕获由构造具有无效值private static class JTable.GenericEditor的特定子类引发的异常。如果您不需要这种通用行为,请考虑将其创建为. 您的方法会相应地更简单。NumberStringPositiveIntegerCellEditorDefaultCellEditorstopCellEditing()

附录:更新为使用RIGHT对齐和常见错误代码。

附录:另请参阅使用编辑器验证用户输入的文本

在此处输入图像描述

    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);
    }
}
于 2011-09-24T13:23:02.833 回答
2

我想到了。false如果给定的数字不是正数,则 覆盖 DefaultCellEditor 并将边框返回/设置为红色。

不幸的是,由于 JTable.GenericEditor 是staticw/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;
        }
    }
于 2011-09-23T16:59:42.800 回答
2

此代码是对已接受答案的一个小改进。如果用户没有输入任何值,点击另一个单元格应该允许他选择另一个单元格。公认的解决方案不允许这样做。

@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()方法。

于 2014-03-10T15:28:44.350 回答
0

所以首先我创建了一个类比来让这个话题更容易理解。
我们有一支笔(editor)。这支笔需要一些墨水(component编辑器使用的,组件的示例JTextFieldJComboBox等等)来书写。

然后这是一支特殊的笔,当我们想用笔写东西时,我们说话(在 GUI 中的打字行为)告诉它写东西(写在 中model)。在写出之前,这支笔中的程序将评估单词是否有效(在stopCellEditing()方法中设置),然后将单词写在纸上(model)。

想解释@trashgod 的答案,因为我在该DefaultCellEditor部分花了 4 个小时。

//first, we create a new class which inherit DefaultCellEditor
private static class PositiveIntegerCellEditor extends DefaultCellEditor {
//create 2 constant to be used when input is invalid and valid
    private static final Border red = new LineBorder(Color.red);
    private static final Border black = new LineBorder(Color.black);
    private JTextField textField;

//construct a `PositiveIntegerCellEditor` object  
//which use JTextField when this constructor is called
    public PositiveIntegerCellEditor(JTextField textField) {
        super(textField);
        this.textField = textField;
        this.textField.setHorizontalAlignment(JTextField.RIGHT);
    }
//basically stopCellEditing() being called to stop the editing mode  
//but here we override it so it will evaluate the input before  
//stop the editing mode
    @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;
        }
//if no exception thrown,call the normal stopCellEditing()
        return super.stopCellEditing();
    }

//we override the getTableCellEditorComponent method so that
//at the back end when getTableCellEditorComponent method is  
//called to render the input, 
//set the color of the border of the JTextField back to black 
    @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);
    }
}  

最后,在你的类中使用这行代码来初始化 JTable 来设置你的DefaultCellEditor

table.setDefaultEditor(Object.class,new PositiveIntegerCellEditor(new JTextField()));

表示您希望应用编辑器的Object.class列类类型(您要使用该笔的纸张的哪一部分。可以是Integer.classDouble.class和其他类)。
然后我们传入new JTextField()PositiveIntegerCellEditor() 构造函数(决定您希望使用哪种类型的墨水)。

如果有什么我误解了,请告诉我。希望这可以帮助!

于 2019-07-26T03:37:16.590 回答