【问题标题】:TornadoFX how to add validation while editing TableViewTornadoFX 如何在编辑 TableView 时添加验证
【发布时间】:2017-07-24 19:12:38
【问题描述】:

考虑以下示例:

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 并尝试在那里验证模型吗?

【问题讨论】:

    标签: kotlin tornadofx


    【解决方案1】:

    您可以实现自己的 cellfactory 并返回一个单元格,该单元格在编辑模式下显示绑定到 ViewModel 的文本字段,否则返回一个标签。或者,如果您对始终显示文本字段感到满意,您可以使用 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
                        }
                    }
                }
            }
        }
    }
    

    看起来像这样:

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

    编辑:我实现了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 开始成为可能。

    【讨论】:

    • 我使用 TornadoFX 1.7.9 中引入的 TableCellFragment 使用更强大的解决方案更新了答案 :)
    • 太棒了!您可以通过使用快照构建来检查它:)
    • 我在我的项目中尝试过,但似乎model.item 可能是null 不知何故(编译器在这里抛出了NPE if (model.number.value == 123L) error("Invalid number") else null)所以我不得不添加额外的null 签入validator lambda在访问模型属性之前。在那之后,它成功了。再次感谢,埃德文 :)
    猜你喜欢
    • 2014-10-19
    • 2017-02-09
    • 2011-05-02
    • 1970-01-01
    • 1970-01-01
    • 2022-08-09
    • 1970-01-01
    • 1970-01-01
    • 2020-06-10
    相关资源
    最近更新 更多