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