1

考虑以下示例:

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

4

1 回答 1

4

您可以实现自己的 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
                    }
                }
            }
        }
    }
}

它看起来像这样:

CellFormat 解决方案

虽然它有效,但由于节点经常重新创建,因此有点浪费。如果性能是一个问题,我会推荐第一种方法,直到我们获得cellFragment对 TableView 的支持,就像我们对 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 开始,这将成为可能。

于 2017-07-24T21:42:54.670 回答