kotlin Tornadofx -如何在每个示例上将参数传递给Fragment

unftdfkk  于 2022-11-16  发布在  Kotlin
关注(0)|答案(2)|浏览(126)

javafx,Kotlin和显然tornadofx我都是新手。

  • 问题 *:

如何在每个示例上向Fragment传递参数?
假设我有一个表视图布局作为我的片段。现在这个片段被用在多个地方,但有不同的数据集。
例如,在以下位置添加片段:

class SomeView : View() {
... 
root += SomeViewFragment::class
}

class SomeAnotherView : View() {
... 
root += SomeViewFragment::class
}

宣告片段:

class SomeViewFragment : Fragment() {
...
    tableview(someDataSetFromRestApiCall) {
    ...
    }
}

如何从SomeView和SomeAnotherView传递不同的someDataSetFromRestApiCall?

0yycz8jy

0yycz8jy1#

让我们从向片段传递数据的最显式方法开始。对于这个TableView示例,您可以在片段内公开一个可观察的列表,并将TableView绑定到该列表。然后,您可以从片段外更新该列表,并将更改反映在片段中。对于该示例,我创建了一个简单的数据对象,该对象具有一个名为SomeItem的可观察属性:

class SomeItem(name: String) {
    val nameProperty = SimpleStringProperty(name)
    var name by nameProperty
}

现在,我们可以定义SomeViewFragment,并将项目属性绑定到TableView:

class SomeViewFragment : Fragment() {
    val items = FXCollections.observableArrayList<SomeItem>()

    override val root = tableview(items) {
        column("Name", SomeItem::nameProperty)
    }
}

如果您稍后更新项目内容,变更将会反映在表格中:

class SomeView : View() {
    override val root = stackpane {
        this += find<SomeViewFragment>().apply {
            items.setAll(SomeItem("Item A"), SomeItem("Item B"))
        }
    }
}

然后,您可以对SomeOtherView执行相同的操作,但使用其他数据:

class SomeOtherView : View() {
    override val root = stackpane {
        this += find<SomeViewFragment>().apply {
            items.setAll(SomeItem("Item B"), SomeItem("Item C"))
        }
    }
}

虽然这很容易理解并且非常明确,但它在组件之间创建了一个非常强的耦合。您可能需要考虑使用作用域来实现这一点。我们现在有两个选项:
1.使用内窥镜内注射
1.让范围包含数据

在内窥镜内使用注射

我们将首先使用选项1,通过注入数据模型。我们首先创建一个数据模型来保存我们的项目列表:

class ItemsModel(val items: ObservableList<SomeItem>) : ViewModel()

现在,我们将ItemsModel注入到Fragment中,并从该模型中提取项:

class SomeViewFragment : Fragment() {
    val model: ItemsModel by inject()

    override val root = tableview(model.items) {
        column("Name", SomeItem::nameProperty)
    }
}

最后,我们需要为每个视图中的片段定义一个单独的作用域,并为该作用域准备数据:

class SomeView : View() {

    override val root = stackpane {
        // Create the model and fill it with data
        val model= ItemsModel(listOf(SomeItem("Item A"), SomeItem("Item B")).observable())

        // Define a new scope and put the model into the scope
        val fragmentScope = Scope()
        setInScope(model, fragmentScope)

        // Add the fragment for our created scope
        this += find<SomeViewFragment>(fragmentScope)
    }
}

请注意,上面使用的setInScope函数将在TornadoFX 1.5.9中提供。同时,您可以用途:

FX.getComponents(fragmentScope).put(ItemsModel::class, model)

让范围包含数据

另一种选择是将数据直接放入作用域中,让我们创建一个ItemsScope

class ItemsScope(val items: ObservableList<SomeItem>) : Scope()

现在,我们的片段将获得SomeItemScope的示例,因此我们将其转换并提取数据:

class SomeViewFragment : Fragment() {
    override val scope = super.scope as ItemsScope

    override val root = tableview(scope.items) {
        column("Name", SomeItem::nameProperty)
    }
}

由于我们不需要模型,因此View现在需要做的工作较少:

class SomeView : View() {

    override val root = stackpane {
        // Create the scope and fill it with data
        val itemsScope= ItemsScope(listOf(SomeItem("Item A"), SomeItem("Item B")).observable())

        // Add the fragment for our created scope
        this += find<SomeViewFragment>(itemsScope)
    }
}

传递参数

EDIT:由于这个问题,我们决定支持使用findinject传递参数。因此,在TornadoFX 1.5.9中,您可以将项目列表作为参数发送,如下所示:

class SomeView : View() {
    override val root = stackpane {
        val params = "items" to listOf(SomeItem("Item A"), SomeItem("Item B")).observable()
        this += find<SomeViewFragment>(params)
    }
}

SomeViewFragment现在可以获取这些参数并直接使用它们:

class SomeViewFragment : Fragment() {
    val items: ObservableList<SomeItem> by param()

    override val root = tableview(items) {
        column("Name", SomeItem::nameProperty)
    }
}

请注意,这涉及到片段内部未经检查的强制转换。

其他选项

您还可以通过EventBus传递参数和数据,EventBus也将包含在即将发布的TornadoFX 1.5.9中。EventBus还支持作用域,这使得定位事件变得更加容易。

进一步阅读

您可以在指南中阅读有关Scopes、EventBus和ViewModel的更多信息:
Scopes
EventBus
ViewModel and Validation

2guxujil

2guxujil2#

我最近一直在想这个问题,我得到的结果是:
您需要创建一个按钮来切换组件

button {
    text = "open fragment"
    action {
        val params = Pair("text", MySting("myText"))
        replaceWith(find<MyFragment>(params))
    }
}

在第二个组件上

class MyFragment : Fragment("Test") {
    var data = SimpleStringProperty()
    override val root = hbox {
        setMinSize(600.0, 200.0)
        label(data) {
            addClass(Styles.heading)
        }
    }

    override fun onDock() {
        data.value = params["text"] as String
    }
}

因此,我们得到第二个组件中的参数

相关问题