TornadoFX cómo agregar validation al editar TableView

Considere el siguiente ejemplo:

class Item(name: String, number: Int) { val nameProperty = SimpleStringProperty(name) var name by nameProperty val numberProperty by lazy { SimpleIntegerProperty(number) } var number by numberProperty } class MainView : View("Example") { val items = listOf(Item("One", 1), Item("Two", 2)).observable() override val root = vbox { tableview(items) { column("Name", Item::nameProperty).makeEditable() column("Number", Item::numberProperty).makeEditable(NumberStringConverter()) enableCellEditing() } } } 

¿Cómo puedo agregar un validator mientras edito las celdas? ¿La única forma de hacerlo es agregar rowExpander con algún campo de textfield e intentar validar un model allí?

Puede implementar su propio cellfactory y devolver una celda que muestre un campo de text vinculado a un ViewModel en modo de edición y una label si no lo está. Alternativamente, si está de acuerdo con mostrar siempre un campo de text, puede usar cellFormat y vincular el elemento actual a un ItemModel para que pueda adjuntar validation:

 class ItemModel(item: Item) : ItemViewModel<Item>(item) { val name = bind(Item::nameProperty) val number = bind(Item::numberProperty) } class MainView : View("Example") { val items = listOf(Item("One", 1), Item("Two", 2)).observable() override val root = vbox { tableview(items) { column("Name", Item::nameProperty).makeEditable() column("Number", Item::numberProperty).cellFormat { val model = ItemModel(rowItem) graphic = textfield(model.number, NumberStringConverter()) { validator { if (model.number.value == 123) error("Invalid number") else null } } } } } } 

Se verá así:

Solución CellFormat

Mientras funciona, es un desperdicio ya que los nodos se recrean con frecuencia. Recomendaría el enfoque número uno si el performance es una preocupación, hasta que cellFragment soporte de cellFragment para TableView como lo tenemos para ListView.

EDIT : implementé el soporte de cellFragment , por lo que es posible crear una solución más robusta que mostrará una label cuando no esté en modo de edición y un campo de text de validation cuando ingrese al modo de edición.

 class ItemModel : ItemViewModel<Item>() { val name = bind(Item::nameProperty) val number = bind(Item::numberProperty) } class MainView : View("Example") { val items = listOf(Item("One", 1), Item("Two", 2)).observable() override val root = vbox { tableview(items) { column("Name", Item::nameProperty).makeEditable() column("Number", Item::numberProperty).cellFragment(NumberEditor::class) } } } class NumberEditor : TableCellFragment<Item, Number>() { // Bind our ItemModel to the rowItemProperty, which points to the current Item val model = ItemModel().bindToRowItem(this) override val root = stackpane { textfield(model.number, NumberStringConverter()) { removeWhen(editingProperty.not()) validator { if (model.number.value == 123L) error("Invalid number") else null } // Call cell.commitEdit() only if validation passes action { if (model.commit()) { cell?.commitEdit(model.number.value) } } } // Label is visible when not in edit mode, and always shows committed value (itemProperty) label(itemProperty) { removeWhen(editingProperty) } } // Make sure we rollback our model to avoid showing the last failed edit override fun startEdit() { model.rollback() } } 

Esto será posible a partir de TornadoFX 1.7.9.

  • Tornadofx Javafx - Cómo volver a cargar una vista / componente
  • Crea una vista arbitraria
  • TornadoFX cómo enlazar Node style (o styleClass) a una propiedad?
  • ¿Cómo puedo crear un encabezado de columna nested / dividido usando TornadoFx?
  • Tornadofx - Cómo pasar el parámetro a Fragment en cada instancia
  • Context de reinicio de JavaFX
  • TornadoFX: Type-Safe CSS con otras bibliotecas
  • TornadoFX JavaFX Sync Desplazarse por las vistas de tabla
  • Cómo instalar un controller de clics en una vista de list dinámica (en tornadofx)
  • El text de la label no se actualiza aunque el hilo de la interfaz de usuario parece responder
  • TornadoFX - Creación de un layout MVP