TornadoFX如何在编辑TableView时添加验证

考虑下面的例子:

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() } } } 

如何在编辑单元格时添加validator ? 唯一的方法是添加rowExpander与一些textfield并尝试在那里验证模型?

您可以实现您自己的cellfactory,并返回一个单元格,在编辑模式下显示绑定到ViewModel的文本字段,如果不是,则返回标签。 另外,如果你总是显示一个文本cellFormat ,你可以使用cellFormat并将当前项绑定到一个ItemModel,这样你可以附加验证:

 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 } } } } } } 

它看起来像这样:

CellFormat解决方案

虽然它起作用,但是由于节点经常被重新创建,这是浪费的。 如果性能是一个问题,我会推荐第一种方法,直到我们像ListView那样获得TableView的cellFragment支持。

编辑 :我实现了cellFragment支持,所以它可以创建一个更强大的解决方案,将显示一个标签,而不是在编辑模式和验证文本字段,当你进入编辑模式。

 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() } } 

这将有可能从TornadoFX 1.7.9开始。