TornadoFX 中的 flowpane 片段

fragment for flowpane in TornadoFX

TornadoFX 文档 describe using the ListCellFragment 将列表控件中的每个单元格绑定到列表中的每个项目模型。我想知道如何在 flowpane 中做类似的事情。我想使用那种 class 在每个单元格中呈现一堆控件和一个 SVG 绘图。 (因此它将替换下面示例代码中的 button 组件,并以某种方式将 shapeItem 模型绑定到它)。

class LibraryView : View("Current Library") {
    val shapeLibraryViewModel : LibraryViewModel by inject()
    override val root = anchorpane{
        flowpane {
            bindChildren(shapeLibraryViewModel.libraryItemsProperty){
               shapeItem -> button(shapeItem.nameProperty)
            }
        }
    }
}

因为我没有看到像列表视图那样的预制 class,也许我需要创建类似的东西...或者可能有更轻量级的方法?

使用 ItemFragment 有点矫枉过正,因为片段的 itemProperty 永远不会改变(只要 libraryItemsProperty 改变,就会为每个项目创建一个新片段。但是,如果您的视图每个项目的逻辑都是实质性的,这种方法将提供一种清晰的方式来分离和包含该逻辑,因此它可能是值得的。这是一个完整的示例,您可以将其用作起点。

class ShapeItemFragment : ItemFragment<ShapeItem>() {
    val shapeModel = ShapeItemModel().bindTo(this)

    override val root = stackpane {
        label(shapeModel.name)
    }
}

class ShapeItem(name: String) {
    val nameProperty = SimpleStringProperty(name)
}

class ShapeItemModel : ItemViewModel<ShapeItem>() {
    val name = bind(ShapeItem::nameProperty)
}

class LibraryViewModel : ViewModel() {
    val libraryItemsProperty = SimpleListProperty<ShapeItem>(
            listOf(
                    ShapeItem("Shape 1"),
                    ShapeItem("Shape 2")
            ).observable()
    )
}

class LibraryView : View("Current Library") {
    val shapeLibraryViewModel: LibraryViewModel by inject()

    override val root = anchorpane {
        flowpane {
            bindChildren(shapeLibraryViewModel.libraryItemsProperty) { shapeItem ->
                val itemFragment = find<ShapeItemFragment>()
                itemFragment.itemProperty.value = shapeItem
                itemFragment.root
            }
        }
    }
}

稍微轻一点的版本是手动将参数传递到您的片段中,并仅扩展片段:

class ShapeItemFragment : Fragment() {
    val item: ShapeItem by param()

    override val root = stackpane {
        label(item.nameProperty)
    }
}

您仍然可以绑定到 ShapeItem 内属性的更改,因为底层项目无论如何都不会更改(从 ItemFragment 可以看出)。

您的 bindChildren 语句将如下所示:

bindChildren(shapeLibraryViewModel.libraryItemsProperty) { shapeItem ->
    find<ShapeItemFragment>(ShapeItemFragment::item to shapeItem).root
}