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.

  • Crea una vista arbitraria
  • Cómo implementar TornadoFX WebEngine Callback en Kotlin
  • ¿Cuál es la mejor práctica para crear un componente de IU personalizado en tornadofx?
  • CellCache se representa inesperadamente en TableView con tornadoFX
  • TornadoFX JavaFX Sync Desplazarse por las vistas de tabla
  • TornadoFX: permite copyr un elemento de una vista de list al portapapeles
  • java.lang.NoSuchMethodException cuando intenta ejecutar la aplicación TornadoFX
  • Kotlin y TornadoFX: ¿une una propiedad observable a una function de recostackción?
  • Enlace de un model de dominio con campos anulables en ItemViewModel
  • Cómo inyectar ItemViewModel en tornadoFx
  • ¿Por qué mi escena es nula?