1

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

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

//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. 表2中产品的金额为负数

我不知道如何查看金额,因为我需要与某个 SKU 关联的金额。如何在一个 BooleanBinding 中使用多个地图创建它?

任何帮助是极大的赞赏!

4

1 回答 1

1

在我看来,您可能会从重新考虑您的对象模型中受益。似乎您Product有两个不同的值amount:一个显示在 table1 中,一个显示在 table2 中。如果您创建类的这两个不同字段Product,那么这一切都会变得容易得多,因为您可以用相同的实际对象表示两个表中的项目(只是在列中显示不同的属性);然后禁用一行的标准就变成了你正在查看的对象的一个​​函数(连同table2.getItems().contains(...))。

另一种选择可能是一个SKU类:

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>与列上的单元格值工厂一起使用,只需查看正确产品的属性即可。这样row.getItem()在 table1 的行工厂中返回SKU对象,并且可以根据需要查看 table2 属性。

如果您真的不能这样做,那么执行此操作的一种方法是维护ObservableMap<String, Double>将 SKU 映射到表 2 中显示的数量。这是一些工作,但还不错:

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()));

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

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()));
        }
    }
});

然后禁用标准可以是

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 中的金额不会改变,除了在表中添加或删除项目。如果需要,可以解决此问题,但它为 table2 项目的侦听器增加了一层复杂性。
于 2014-10-29T15:15:10.760 回答