首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JavaFX:与多个EasyBind映射绑定的BooleanBindings

JavaFX:与多个EasyBind映射绑定的BooleanBindings
EN

Stack Overflow用户
提问于 2014-10-29 13:59:14
回答 1查看 588关注 0票数 1

这个问题进一步深入到了JavaFX: Disable multiple rows in TableView based on other TableView停止的地方。我想提出一个更一般性的话题,其他人也可以从中受益。

我还有两个桌面视图。当table2包含相同的对象时,我还希望禁用table1中的行。这是通过以下代码实现的:

代码语言:javascript
复制
//Check if a row needs to be disabled: this is achieved with a rowfactory
ObservableList<String> listOfSKUs = EasyBind.map(table1.getItems(),Product::getSKU);
table2.setRowFactory(tv -> {

    TableRow<Product> row = new TableRow<>();

    //The row doesnt need to be checked when it is empty, thats the first part
    //The second part is a big OR: the row is a gift card OR the listOfSkus contains the row. In this last one, the amount also needs to be checked.

    row.disableProperty().bind(Bindings.createBooleanBinding( () -> 
        row.getItem() != null && 
        (row.getItem().getProductName().equals("Kadobon") ||
        (listOfSKUs.contains(row.getItem().getSKU()) //&& some part to check for the amount)  
        ), listOfSKUs, row.itemProperty() ));

     return row;

});

现在,我只希望在下列情况下禁用行:

  1. 来自table1的产品的SKU也在table2中(现在起作用了)
  2. table2中的产品数量为负数。

我不知道如何检查金额,因为我需要与某些SKU相关的金额。如何在一个BooleanBinding中使用多个映射来创建这个映射?

任何帮助都是非常感谢的!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-29 15:15:10

在我看来,重新考虑对象模型可能会给您带来好处。您的Product似乎有两个不同的值,您称之为amount:一个在table1中显示,另一个在table2中显示。如果使用Product类的这两个不同字段,那么所有这些都变得容易得多,因为您可以用相同的实际对象(只是在列中显示不同的属性)来表示两个表中的项;然后禁用行的条件就变成了您正在查看的对象的一个函数(以及table2.getItems().contains(...))。

另一个选项可能是一个SKU类:

代码语言:javascript
复制
public class SKU {

    private final StringProperty sku = ... ;

    // Obviously use more meaningful names for these:
    private final ObjectProperty<Product> table1Product = ... ;
    private final ObjectProperty<Product> table2Product = ... ;

    // getters, setters etc...

}

然后,这两个表都可以是TableView<SKU>,其中的单元格值工厂位于列上,只需查看来自正确产品的属性。这样,表1的行工厂中的row.getItem()将返回SKU对象,并可以根据需要查看table2属性。

如果您真的不能做到这一点,那么一种方法就是维护一个ObservableMap<String, Double>,它将SKU映射到table2中显示的数量。这是一些工作,但也不算太糟:

代码语言:javascript
复制
ObservableMap<String, Double> skuAmountLookup = table2.getItems().stream().collect(
    Collectors.toMap(Product::getSKU, Product::getAmount,
    // the next argument is a merge function, which is used if there are two (or more) items
    // in table2 with the same SKU. This function would replace the first value by the second.
    // If the SKUs are unique it doesn't really matter what you have here...
    (x, y) -> y,
    () -> FXCollections.observableHashMap()));

现在,您需要在表内容更改时保持地图更新:

代码语言:javascript
复制
table2.getItems().addListener((ListChangeListener.Change<? extends Product> change) -> {
    // can just do skuAmountLookup.clear(); followed by skuAmountLookup.putAll(...)
    // passing in the same data used above to initialize it
    // That's pretty inefficient though, the following will just update what's needed.
    // This assumes SKUs are unique in table 2:
    while (change.next()) {
        if (change.wasAdded()) {
            change.getAddedSubList().forEach(product -> 
                skuAmountLookup.put(product.getSKU(), product.getAmount()));
        }
        if (change.wasRemoved()) {
            change.getRemoved().forEach(product -> skuAmountLookup.remove(product.getSKU()));
        }
    }
});

然后禁用条件可以类似于

代码语言:javascript
复制
row.disableProperty().bind(Bindings.createBooleanBinding(
    () -> row.getItem() != null &&
          skuAmountLookup.containsKey(row.getItem().getSKU()) &&
          skuAmountLookup.get(row.getItem().getSKU()) < 0, 
    skuAmountLookup,
    row.itemProperty()));

我什么都没试过,但应该管用的。这里有两个假设:

  1. SKU在表2中是唯一的
  2. 除了从表中添加或删除的项外,表2中的金额不会改变。如果需要的话,这是可以解决的,但它为表2项上的侦听器增加了一层复杂性。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26632292

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档