这个问题更进一步,JavaFX:基于其他TableView停止禁用TableView中的多行。我想提出一个更一般的话题,其他人也可以从中受益。
我还有两个表视图。当表1包含相同的对象时,我还想禁用表2中的一行。这是通过以下代码实现的:
//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中产品的SKU也在表2中(现在可以使用)
- 表2中的产品数量为负数
我不知道如何检查金额,因为我需要与特定SKU关联的金额。如何在一个BooleanBinding中创建多个贴图?
非常感谢您的帮助!
在我看来,您可能会从重新考虑对象模型中受益。您的Product
似乎有两个不同的值,您称之为amount
:一个显示在表1中,另一个则显示在表2中。如果您使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>
,列上的单元格值工厂只查看正确产品的属性。这样,表1的行工厂中的row.getItem()
返回SKU
对象,并可以根据需要查看表2的属性。
如果你真的不能做到这一点,那么一种方法就是维护一个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()));
我还没试过这些,但应该有效。这里有两个假设:
- SKU在表2中是唯一的
- 除了表中添加或删除的项目外,表2中的金额不会发生变化。如果需要,这可以解决,但它为表2的项的侦听器增加了一层复杂性