绑定一个 observable 属性 到一个集合函数?

Bind an observable property to a collection function?

我有一个 class Market,其中包含一个名为 m_updatesMarketUpdate 个对象的集合。对于 UI,我使用类型安全的构建器在表视图中创建列,如下所示:

override val root = tableview<Market> {
    val sortedMarketList = SortedList<Market>(markets)
    sortedMarketList.comparatorProperty().bind(this.comparatorProperty())
    items = sortedMarketList
...
column("Strikes", Market::m_strikes)
...

m_strikes 属性 只是一个 Market 对象直接拥有的 SimpleIntegerProperty。但是,我需要能够构建像这样的列:

...
column("Created At", Market::m_updates::first::m_time)
...

...
column("Last Update", Market::m_updates::last::m_time)
...

其中 m_timeMarketUpdate 对象拥有的 SimpleLongProperty。更新 Market 对象时,新的 MarketUpdate 对象将添加到 m_updates 集合的末尾。这意味着绑定需要自动从一个对象转换到另一个对象,并且需要通知 tableview 并更新自身以反映新对象中的数据。我认为通过上述集合的 first()last() 函数进行绑定以一种非常简单的方式捕捉了这个想法,但它不会编译。

有很多属性,例如 m_strikesm_time。我怎样才能优雅地实现这一目标?

如果我理解你的用例,你想要做的是创建一个可观察值,表示给定 Market 对象中第一次和最后一次更新的时间 属性。为此,您可以根据每个 Market 对象内的 updates 列表创建一个 objectBinding,然后提取 first()last() 元素的 timeProperty.在以下示例中,只要您在任何 Market 对象中扩充更新列表,TableView 就会更新。

请记住,该示例要求每个 Market 至少有一个更新。如果这不是您的情况,请确保相应地处理 null。

class Market {
    val updates = FXCollections.observableArrayList<MarketUpdate>()
}

class MarketUpdate {
    val timeProperty = SimpleObjectProperty(LocalDateTime.now())
}

class MarketList : View("Markets") {
    val markets = FXCollections.observableArrayList<Market>()
    val data = SortedFilteredList<Market>(markets)

    override val root = borderpane {
        prefWidth = 500.0

        center {
            tableview(markets) {
                column<Market, LocalDateTime>("Created at", { objectBinding(it.value.updates) { first() }.select { it!!.timeProperty } })
                column<Market, LocalDateTime>("Last update", { objectBinding(it.value.updates) { last() }.select { it!!.timeProperty } })
            }
        }
        bottom {
            toolbar {
                // Click to add an update to the first entry
                button("Add update").action {
                    markets.first().updates.add(MarketUpdate())
                }
            }
        }
    }

    init {
        // Add some test entries
        markets.addAll(
                Market().apply { updates.addAll(MarketUpdate(), MarketUpdate(), MarketUpdate()) },
                Market().apply { updates.addAll(MarketUpdate(), MarketUpdate(), MarketUpdate()) },
                Market().apply { updates.addAll(MarketUpdate(), MarketUpdate(), MarketUpdate()) },
                Market().apply { updates.addAll(MarketUpdate(), MarketUpdate(), MarketUpdate()) }
        )
    }
}

我使用了 SortedFilteredList 来简化排序处理。排序在这里起作用的原因是,列实际上由 LocalDateTime 值表示。

我希望这能给你一些想法:)