tablemodellistener - obtener datos de un jtable en java netbeans
¿Puede un Jtable guardar datos cada vez que una celda pierde el foco? (3)
El alto nivel: tengo una JTable que el usuario puede usar para editar datos.
Cada vez que el usuario presione Enter o Tab para terminar la edición, los datos se guardan (estoy asustando que "guardado" realmente significa "el método setValueAt () de TableModel se llama".)
Si el usuario abandona la celda de alguna otra forma después de realizar una edición, los nuevos datos no se guardan y el valor permanece como estaba. Entonces, por ejemplo, si el usuario cambia un valor y luego hace clic en otro widget en la pantalla, el cambio no se "pega".
Creo que este es el comportamiento predeterminado para una JTable llena de cadenas, ¿sí?
Por diversas razones, el comportamiento deseado es que la célula guarde todas y cada una de las ediciones cuando el usuario abandone la celda. ¿Cuál es la mejor / forma correcta de hacer que Swing haga esto?
Necesita agregar un oyente de enfoque . Dado que JTable es básicamente un contenedor de sus componentes de celda, en realidad desea que el oyente de enfoque para cada celda de su tabla tenga que comportarse de la manera que usted indicó.
Para hacer esto, deberá crear un editor de celda personalizado, que envuelva el componente de la celda que tiene un detector de enfoque registrado. Y cuando recibe la devolución de llamada para la pérdida de evento de foco, guarda los datos, según lo requiera.
Esto prácticamente detalla la mayoría de lo que necesita hacer . Los detalles de implementar el oyente de enfoque no están ahí, pero eso es bastante sencillo.
Digamos que usas JTextComponent como tu componente celular. Entonces:
public void focusLost(FocusEvent e) {
JTextComponent cell = (JTextComponent) e.getSource();
String data = cell.getText();
// TODO: save the data for this cell
}
[ps edit]:
El hilo que te está llamando con este evento es el hilo de envío. NO lo use para acciones con alta latencia. Pero si solo estás volteando bits en el montón, debería estar bien.
Una de las soluciones simples propuestas
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
es bueno solo para columnas String. El problema es si tengo, por ejemplo, el tipo Float de la columna que se está editando, ingrese una cadena vacía en la celda correspondiente y luego CellEditorRemover.propertyChange()
clic en cualquier otro control de la ventana: Java arroja NullPointerException
en el método CellEditorRemover.propertyChange()
de JTable.java
. Utiliza la llamada getCellEditor()
para detener o cancelar la edición, pero devuelve null
en este caso. Si el valor ingresado no está vacío o si terminateEditOnFocusLost
indicador terminateEditOnFocusLost
todo está bien. Probablemente, la situación descrita es un error.
Espero poder proporcionar una solución basada en una de las publicaciones anteriores. No es tan trivial como suponía antes, pero me parece que funciona. Tuve que heredar mi propio editor de celda del editor de celda predeterminado y mi propio campo de texto de JTextField
que tiene FocusListener
. Este oyente de enfoque funciona bien cuando la celda de edición pierde un foco, y un foco ganado por otro control de la ventana. Pero en el caso de los cambios de selección de células, el oyente de enfoque es "sordo". Es por eso que también tengo que recordar el valor previamente válido antes de comenzar la edición para restaurarlo si el valor ingresado no será válido.
Vea el código a continuación. Probado con Double
, Float
e Integer
, pero espero que esto también funcione con Byte
y String
.
Campo de texto con oyente de enfoque:
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();
}
});
}
}
Clase de editor celular predeterminado:
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;
}
Es el código de inicialización de la tabla que debe agregar lo siguiente:
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));
Espero, esto ayudará a alguien que tenga el mismo problema.
Table Stop Editing explica qué está sucediendo y ofrece un par de soluciones simples.