фрагмент для панели в TornadoFX

Документы TornadoFX описывают использование ListCellFragment для привязки каждого ячейку в элементе управления списком для каждой модели элемента в списке. Мне интересно, как сделать что-то подобное в flowpane. Я хотел бы использовать такой класс для визуализации набора элементов управления и рисунка 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)
            }
        }
    }
}

Поскольку я не вижу готового класса, такого как класс для представления списка, возможно, мне нужно будет создать что-то похожее на него ... или, может быть, есть более легкий подход?


person DanielMcQ    schedule 21.05.2018    source источник


Ответы (1)


Использование 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
}
person Edvin Syse    schedule 21.05.2018