Jtable可以在单元格失去焦点时保存数据吗?

2022-09-01 16:56:45

高级别:我有一个JTable,用户可以使用它来编辑数据。

每当用户按 Enter 或 Tab 键完成编辑时,数据就会被保存(我确信“已保存”实际上意味着“TableModel 的 setValueAt() 方法被调用”)。

如果用户在进行编辑后以任何其他方式离开单元格,则不会保存新数据,并且值将保持原样。因此,例如,如果用户更改了一个值,然后单击屏幕上的其他一些小部件,则更改不会“坚持”。

我相信这是充满字符串的JTable的默认行为,是吗?

出于各种原因,所需的行为是让单元格在用户离开单元格时保存任何和所有编辑。让Swing做到这一点的最佳/正确的方法是什么?


答案 1

表格停止编辑解释了发生了什么,并给出了几个简单的解决方案。


答案 2

提出的简单解决方案之一

table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

仅适用于字符串列。问题是,例如,如果我有正在编辑的列的浮点型,在相应的单元格中输入一个空字符串,然后单击窗口的任何其他控件 - Java会抛出方法。它使用调用来停止或取消编辑,但在这种情况下返回。如果输入的值不为空,或者如果我删除标志,一切都很好。可能,所描述的情况是一个错误。NullPointerExceptionCellEditorRemover.propertyChange()JTable.javagetCellEditor()nullterminateEditOnFocusLost

我希望我能根据之前的帖子之一提供解决方案。它并不像我以前想象的那样微不足道,但在我看来它是有效的。我不得不从默认单元格编辑器继承我自己的单元格编辑器和我自己的文本字段,其中有.当编辑单元格失去焦点以及由窗口的另一个控件获得的焦点时,此焦点侦听器工作正常。但在细胞选择变化的情况下,焦点听众是“聋子”。这就是为什么在编辑开始之前,我还必须记住以前的有效值,以便在输入的值无效时恢复它。JTextFieldFocusListener

请参阅下面的代码。使用 和 进行了测试,但我希望这也适用于 和 。DoubleFloatIntegerByteString

带焦点侦听器的文本字段:

public class TextFieldCell extends JTextField {
    public TextFieldCell(JTable cellTable) {
        super();                            // calling parent constructor
        final JTable table = cellTable;     // this one is required to get cell editor and stop editing

        this.addFocusListener(new FocusListener() {
            public void focusGained(FocusEvent e) {
            }

            // this function successfully provides cell editing stop
            // on cell losts focus (but another cell doesn't gain focus)
            public void focusLost(FocusEvent e) {
                CellEditor cellEditor = table.getCellEditor();
                if (cellEditor != null)
                    if (cellEditor.getCellEditorValue() != null)
                        cellEditor.stopCellEditing();
                    else
                        cellEditor.cancelCellEditing();
            }
        });
    }
}

默认单元格编辑器类:

class TextFieldCellEditor extends DefaultCellEditor {
TextFieldCell textField;    // an instance of edit field
Class<?> columnClass;       // specifies cell type class
Object valueObject;         // for storing correct value before editing
public TextFieldCellEditor(TextFieldCell tf, Class<?> cc) {
    super(tf);
    textField = tf;
    columnClass = cc;
    valueObject = null;
}

@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
    TextFieldCell tf = (TextFieldCell)super.getTableCellEditorComponent(table, value, isSelected, row, column);
    if (value != null) {
        tf.setText(value.toString());
    }
    // we have to save current value to restore it on another cell selection
    // if edited value couldn't be parsed to this cell's type
    valueObject = value;
    return tf;
}

@Override
public Object getCellEditorValue() {
    try {
        // converting edited value to specified cell's type
        if (columnClass.equals(Double.class))
            return Double.parseDouble(textField.getText());
        else if (columnClass.equals(Float.class))
            return Float.parseFloat(textField.getText());
        else if (columnClass.equals(Integer.class))
            return Integer.parseInt(textField.getText());
        else if (columnClass.equals(Byte.class))
            return Byte.parseByte(textField.getText());
        else if (columnClass.equals(String.class))
            return textField.getText();
    }
    catch (NumberFormatException ex) {

    }

    // this handles restoring cell's value on jumping to another cell
    if (valueObject != null) {
        if (valueObject instanceof Double)
            return ((Double)valueObject).doubleValue();
        else if (valueObject instanceof Float)
            return ((Float)valueObject).floatValue();
        else if (valueObject instanceof Integer)
            return ((Integer)valueObject).intValue();
        else if (valueObject instanceof Byte)
            return ((Byte)valueObject).byteValue();
        else if (valueObject instanceof String)
            return (String)valueObject;
    }

    return null;
}

它是表初始化的代码,您必须添加以下内容:

myTable.setDefaultEditor(Float.class, new TextFieldCellEditor(new TextFieldCell(myTable), Float.class));
myTable.setDefaultEditor(Double.class, new TextFieldCellEditor(new TextFieldCell(myTable), Double.class));
myTable.setDefaultEditor(Integer.class, new TextFieldCellEditor(new TextFieldCell(myTable), Integer.class));

希望,这将帮助有同样问题的人。


推荐