TableView Editable (JavaFX)

Seguimos viendo más posibilidades del control JavaFX TableView, esta vez veremos cómo editar los datos que son mostrados en el control y veremos cómo personalizar el control usado para la edición de las celdas, por ejemplo: para editar un dato tipo fecha usaremos un control para el manejo de fechas DatePicker, del mismo modo para los demás datos usaremos el control correspondiente.

Para hacer el TableView editable usaremos el método table_view.setEditable(true), para controlar la edición el TableColumn soporta tres eventos: onEditStart, onEditCommit, onEditCancel, el primero el lanzado cuando la celda cambia al modo edición, el segundo al confirmar la edición, por ejemplo al presionar la tecla ENTER, y el último al cancelar la edición por ejemplo al presionar la tecla ESC.

Editar TableView con TextField


Las columnas de un TableView que presentan información de tipo String pueden ser editadas usando TextFieldTableCell esta clase genera un control TextField que permite editar el texto que contiene una celda, lo habilitamos haciendo doble clic sobre la celda, el método estático TextFieldTableCell.forTableColumn() crea la celda editable.

TableColumn<Persona, String> tc_nombre = new TableColumn<>("Nombre");
tc_nombre.setCellValueFactory(new PropertyValueFactory<Persona, String>("Nombre"));
tc_nombre.setCellFactory(TextFieldTableCell.forTableColumn());

textfiled tableview
Como lo mencionamos anteriormente tenemos tres eventos disponibles para responder a las acciones de edición, para este ejemplo veremos el evento OnEditCommit producido al aceptar la edición, los demás eventos funcionan de manera similar, usaremos los métodos getNewValue() y getOldValue() para obtener el valore nuevo y el anterior a la edición, el método getRowValue() nos devuelve el objeto que representa la fila.

tc_nombre.setOnEditCommit(data -> {
    System.out.println("Nuevo Nombre: " +  data.getNewValue());
    System.out.println("Antiguo Nombre: " + data.getOldValue());

    Persona p = data.getRowValue();
    p.setNombre(data.getNewValue());

    System.out.println(p);
});

Aprovechamos este evento para guardar los nuevos datos, si tuviésemos una base de datos podríamos guardar estos nuevos cambios.

Algunas veces necesitamos mostrar y editar datos que no son de tipo String, por ejemplo una fecha aunque se puede mostrar y editar como texto es un objeto LocalDate por ello requerimos un convertidor de String a LocalDate y viceversa, la clase StringConverter nos permite crear estos convertidores, LocalDateStringConverter nos sirve a nuestros propósitos.

TableColumn<Persona, LocalDate> tc_nacimiento = new TableColumn<>("Fecha de Nacimiento");
tc_nacimiento.setCellValueFactory(new PropertyValueFactory<Persona, LocalDate>("nacimiento"));
LocalDateStringConverter converter = new LocalDateStringConverter();
tc_nacimiento.setCellFactory(TextFieldTableCell.<Persona, LocalDate>forTableColumn(converter));
tc_nacimiento.setOnEditCommit(data -> { data.getRowValue().setNacimiento(data.getNewValue()); });

Editar TableView con Choice Box


Al activar la edición de una celda con este control el mismo despliega una lista de elementos seleccionables, para este tutorial lo usaremos para mostrar la lista de posibles géneros de una persona, el usuario selecciona el que más le parezca, en ese momento se produce el evento onEditCommit.

Esta celda editable la creamos usando el método estático forTableColumn() debemos indicarle cuales son los elementos a mostrar, pertenece a la clase ChoiceBoxTableCell.

TableColumn<Persona, Persona.Genero> tc_genero = new TableColumn<>("Genero");
tc_genero.setCellValueFactory(new PropertyValueFactory<Persona, Persona.Genero>("Genero"));
tc_genero.setCellFactory(ChoiceBoxTableCell
        .forTableColumn(Persona.Genero.MASCULINO, Persona.Genero.FEMENINO));

choice box tableview

Editar TableView con Check Box


Un Check Box es un control que normalmente nos permite representar dos estados, habilitado y deshabilitado, por ello es común usarlo para representar datos de tipo Boolean lo creamos con el método forTableColumn() de la clase CheckBoxTableCell debemos indicarle a que columna pertenece.

TableColumn<Persona, Boolean> tc_activo = new TableColumn<>("Activo");
tc_activo.setCellValueFactory(cell -> {
    Persona p = cell.getValue();
    return new ReadOnlyBooleanWrapper(p.getActivo());
});
tc_activo.setCellFactory(CheckBoxTableCell.forTableColumn(tc_activo));

check box tableview
Este control no produce ninguno de los tres eventos de edición antes mencionados.

Si usamos propiedades JavaFX el control de edición de la celda se enlaza con la propiedad y cambia automáticamente su valor cuando este es editado, como ejemplo cambiaremos la propiedad activo para usar propiedades JavaFX, la modificación en la clase Persona es la siguiente:

private BooleanProperty _activo;

public final BooleanProperty activoProperty() { return this._activo; }

public final Boolean getActivo() { return _activo.get(); }

public final void setActivo(Boolean activo) { this._activo.set(activo); }

Al crear la columna editable lo hacemos del siguiente modo:

TableColumn<Persona, Boolean> tc_activo = new TableColumn<>("Activo");
tc_activo.setCellValueFactory(cell -> cell.getValue().activoProperty());
tc_activo.setCellFactory(CheckBoxTableCell.forTableColumn(tc_activo));

Usando propiedades se aprovechan todas las capacidades de los controles JavaFX, por lo que recomiendo siempre utilizarlas, sin embargo también tengamos en cuanta que podemos usar clases con propiedades JavaBeans.

GitHub: Edición de TableView JavaFX

Comentarios

  1. Como puedo mantener el estilo del TextField incluso cuando no esta enfocada la columna ?

    ResponderEliminar
  2. Buenas tardes. Respecto al ChoiceBox, tienes idea de como hacer para que ésa columna permanezca siempre activo el ChoiceBox? Que al dar un solo click sobre la celda, se desplieguen los items.... Pues por defecto, hay que hacer 2 clicks incluso hasta tres, para poder desplegar los items y hacer la seleccion.

    ResponderEliminar
    Respuestas
    1. Lo que pasa es que para activar el modo edición de una celda hay que hacer doble clic, el tercero sería para desplegar el ChoiceBox, si deseas cambiar este comportamiento deberás sobre-escribir la clase TableView para activar la edición de otra manera, es un poco complicado pero se puede hacer.

      Eliminar
    2. Ya lo logré, con el evento MOUSE_CLICKED, al hacer click sobre la columna que se quiere activar la edición, llamamos al metodo edit del TableView, y ya con sólo 2 click's continuos o con lapso de tiempo entre click, uno para activar la celda y otro para desplegar el ChoiceBox... Me gusta así.

      Eliminar
  3. Hola, Tengo una columna con un campo double que me esta editando bien, pero me gustaria que en el modo edicion no permita ingresar letras, como podria hacer ese control?

    ResponderEliminar

Publicar un comentario

Temas relacionados

Entradas populares de este blog

tkinter Grid

Histogramas OpenCV Python

Modelo de Iluminación Phong - Tutorial OpenGL

tkinter Canvas