Java Jtable 可以在单元格失去焦点时保存数据吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1652942/
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
Can a Jtable save data whenever a cell loses focus?
提问by Electrons_Ahoy
The high level: I have a JTable that the user can use to edit data.
高层次:我有一个 JTable,用户可以使用它来编辑数据。
Whenever the user presses Enter or Tab to finish editing, the data is saved (I'm asusming that "saved" really means "the TableModel's setValueAt() method is called".)
每当用户按 Enter 或 Tab 完成编辑时,数据就会被保存(我假设“保存”实际上意味着“调用了 TableModel 的 setValueAt() 方法”。)
If the user leaves the cell in any other way after making an edit, the new data is not saved and the value stays the way it was. So, for example, if the user changes a value and then clicks on some other widget on the screen, the change doesn't "stick."
如果用户在进行编辑后以任何其他方式离开单元格,则不会保存新数据并且值保持原样。因此,例如,如果用户更改一个值,然后单击屏幕上的某个其他小部件,则更改不会“保持不变”。
I believe that this is the default behavior for a JTable full of Strings, yes?
我相信这是一个充满字符串的 JTable 的默认行为,是吗?
For a variety of reasons, the desired behavior is for the cell to save any and all edits whenever the user leaves the cell. What's the best/right way to get Swing to do this?
出于各种原因,单元格希望在用户离开单元格时保存任何和所有编辑。让 Swing 做到这一点的最佳/正确方法是什么?
回答by alphazero
You need to add a focus listener. Given that JTable is basically a container of its cell components, you actually want the focus listener for every cell in your table that needs to behave in the way you indicated.
您需要添加一个焦点侦听器。鉴于 JTable 基本上是其单元格组件的容器,您实际上希望表格中每个单元格的焦点侦听器都需要按照您指示的方式运行。
To do this, you will need to create custom cell editor, which wraps the cell component that has a registered focus listener. And when you get the callback for the loss of focus event, you do the data save, as you require.
为此,您需要创建自定义单元格编辑器,它包装具有注册焦点侦听器的单元格组件。当您获得失去焦点事件的回调时,您可以根据需要进行数据保存。
This pretty much details most of what you need to do. The details of implementing the focus listener is not there, but that is fairly straightforward.
这几乎详细说明了您需要执行的大部分操作。没有实现焦点侦听器的细节,但这相当简单。
Lets say you do use a JTextComponent as your cell component. Then:
假设您确实使用 JTextComponent 作为单元格组件。然后:
public void focusLost(FocusEvent e) {
JTextComponent cell = (JTextComponent) e.getSource();
String data = cell.getText();
// TODO: save the data for this cell
}
[p.s. edit]:
[ps编辑]:
The thread that is calling you with this event is the dispatch thread. Do NOT use it for actions with high latency. But if you are just flipping bits in the heap, it should be ok.
使用此事件调用您的线程是调度线程。不要将它用于具有高延迟的操作。但是如果你只是在堆中翻转位,那应该没问题。
回答by camickr
Table Stop Editingexplains whats happening and gives a couple simple solutions.
Table Stop Editing解释了正在发生的事情并提供了几个简单的解决方案。
回答by ezze
One of the simple solutions proposed
提出的简单解决方案之一
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
is good only for String columns. The problem is if I have, for example, Float type of the column being edited, enter an empty string in corresponding cell and then click on any other control of the window – Java throws NullPointerException
in CellEditorRemover.propertyChange()
method of JTable.java
. It uses getCellEditor()
call to stop or cancel editing but it returns null
in this case. If the value entered is not empty or if I remove terminateEditOnFocusLost
flag everything is fine. Probably, the situation described is a bug.
仅适用于字符串列。问题是如果我,例如,柱的浮子式被编辑,在对应的单元格中输入一个空字符串,然后点击窗口的任何其他控制-爪哇抛出NullPointerException
中CellEditorRemover.propertyChange()
的方法JTable.java
。它使用getCellEditor()
call 来停止或取消编辑,但null
在这种情况下它会返回。如果输入的值不为空或者我删除了terminateEditOnFocusLost
标志,一切都很好。可能,所描述的情况是一个错误。
I hope I can provide a solution based on one of the previous posts. It's not so trivial as I supposed before but seems to me it works.
I had to inherit my own cell editor from default cell editor and my own text field from JTextField
which has FocusListener
. This focus listener works fine when editing cell loses a focus, and a focus gained by another control of the window. But in the case of cell selection changes focus listener is “deaf”. That's why I also have to remember previously valid value before editing start to restore it if the entered value will be invalid.
我希望我可以根据以前的帖子之一提供解决方案。这并不像我之前想象的那么微不足道,但在我看来它是有效的。我必须从默认单元格编辑器和我自己的文本字段继承我自己的单元格编辑器,JTextField
其中有FocusListener
. 当编辑单元格失去焦点并且焦点由窗口的另一个控件获得时,此焦点侦听器工作正常。但是在单元格选择变化的情况下,监听器是“聋”的。这就是为什么我还必须在编辑之前记住以前有效的值,如果输入的值无效,则开始恢复它。
See the code below. Tested with Double
, Float
and Integer
, but I hope this will also work with Byte
and String
.
请参阅下面的代码。用Double
, Float
and测试过,Integer
但我希望这也适用于Byte
and String
。
Text field with focus listener:
带有焦点侦听器的文本字段:
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();
}
});
}
}
Default cell editor class:
默认单元格编辑器类:
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;
}
It the code of table initialization you have to add the following:
在表初始化的代码中,您必须添加以下内容:
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));
Hope, this will help somebody who have the same problem.
希望,这会帮助有同样问题的人。