只要单元格失去焦点,Jtable可以保存数据吗?

时间:2009-10-31 00:23:50

标签: java swing jtable

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

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

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

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

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

3 个答案:

答案 0 :(得分:26)

Table Stop Editing解释了发生了什么,并给出了几个简单的解决方案。

答案 1 :(得分:14)

提出的一个简单解决方案

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

仅适用于String列。问题是如果我有,例如,正在编辑的列的Float类型,在相应的单元格中输入一个空字符串,然后单击该窗口的任何其他控件 - Java NullPointerException方法中CellEditorRemover.propertyChange()抛出JTable.java getCellEditor()。它使用null调用来停止或取消编辑,但在这种情况下会返回terminateEditOnFocusLost。如果输入的值不为空或者我删除了JTextField标记,则一切正常。可能,描述的情况是一个错误。

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

请参阅下面的代码。使用FloatIntegerByte进行了测试,但我希望这也适用于Stringpublic 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));

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

{{1}}

希望,这将有助于遇到同样问题的人。

答案 2 :(得分:5)

您需要添加focus listener。鉴于JTable基本上是其单元组件的容器,实际上您希望表中每个单元的焦点侦听器需要按照您指示的方式运行。

为此,您需要创建自定义单元格编辑器,该编辑器包装具有已注册焦点侦听器的单元组件。当您收到失去焦点事件的回调时,您可以根据需要进行数据保存。

This pretty much details most of what you need to do。实现焦点监听器的细节不存在,但这是相当简单的。

假设您确实使用JTextComponent作为单元组件。然后:

public void focusLost(FocusEvent e) {
   JTextComponent cell = (JTextComponent) e.getSource();  
   String data = cell.getText();

   // TODO: save the data for this cell
}

[P.S。编辑]:

使用此事件调用您的线程是调度线程。请勿将其用于具有高延迟的操作。但是,如果你只是在堆中翻转位,那应该没问题。