java 如何将 JTable 单元格输入标记为无效?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7531513/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 20:21:40  来源:igfitidea点击:

How to mark JTable cell input as invalid?

javaswingvalidationjtabletablecelleditor

提问by Cuga

If I take a JTableand specify a column's classtype on it's model as follows:

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

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

Then whenever a user tries to enter a doublevalue into the table, Swing automatically rejects the input and sets the cell's outline to red.

然后每当用户尝试double在表格中输入一个值时,Swing 会自动拒绝输入并将单元格的轮廓设置为红色。

I want the same effect to occur when someone enters a 'negative or 0' input to the cell. I've got this:

当有人向单元格输入“负或 0”输入时,我希望发生相同的效果。我有这个:

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

This prevents the cell from accepting any non-positive values, but it doesn't set the color to red and leave the cell as editable.

这可以防止单元格接受任何非正值,但它不会将颜色设置为红色并使单元格保持可编辑状态。

I tried looking into how JTable's doing the rejection by default, but I can't seem to find it.

我尝试查看 JTable 默认情况下如何进行拒绝,但我似乎找不到它。

How can I make it reject the non-positive input the same way it rejects the non-Integer input?

如何让它像拒绝非整数输入一样拒绝非正输入?

回答by trashgod

The private static class JTable.GenericEditoruses introspection to catch exceptions raised by constructing specific Numbersubclasses with invalid Stringvalues. If you don't need such generic behavior, consider creating PositiveIntegerCellEditoras a subclass of DefaultCellEditor. Your stopCellEditing()method would be correspondingly simpler.

private static class JTable.GenericEditor用内省通过构建具体提出捕获异常Number的子类无效String值。如果您不需要这种通用行为,请考虑将其创建PositiveIntegerCellEditorDefaultCellEditor. 你的stopCellEditing()方法会相应地更简单。

Addendum: Updated to use RIGHTalignment and common error code.

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

Addendum: See also Using an Editor to Validate User-Entered Text.

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

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

回答by Cuga

I figured it out. Override the DefaultCellEditor and return false/ set the border to red if the number given is not positive.

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

Unfortunately, since JTable.GenericEditor is staticw/ defaultscope, I'm unable to override the GenericEditorto provide this functionality and have to re-implement it w/ a few tweaks, unless someone has a better way of doing this, which I'd like to hear.

不幸的是,由于 JTable.GenericEditor 是staticdefault范围的,我无法覆盖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;
        }
    }

回答by Jan Bodnar

This code is a small improvement of the accepted answer. If the user does not enter any value, clicking on another cell should allow him to select another cell. The accepted solution does not allow this.

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

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

This solution checks for empty text. In case of an empty text, we call the stopCellEditing()method.

此解决方案检查空文本。在空文本的情况下,我们调用该stopCellEditing()方法。

回答by Sprint

So first I created an analogy to make this topic easier to be understood.
We have a pen(editor). This pen will need some ink(The componentthat the editor use, an example of a component is JTextField,JComboBoxand so on) to write.

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

Then this is a special pen when we want to write something using the pen, we speak(typing behavior in the GUI) to tell it to write something(write in the model). Before writing it out, the program in this pen will evaluate whether the word is valid(which being set in stopCellEditing()method), then it writes the words out on paper(model).

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

Would like to explain @trashgod's answer since I have spent 4 hours on the DefaultCellEditorSection.

想解释@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);
    }
}  

Lastly, use this line of code in your class that initialise JTable to set your DefaultCellEditor

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

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

The Object.classmeans which type of column class you wish to apply the editor (Which part of paper you want to use that pen. It can be Integer.class,Double.classand other class).
Then we pass new JTextField()in PositiveIntegerCellEditor() constructor(Decide which type of ink you wish to use).

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

If anything that I misunderstood please tell me. Hope this helps!

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