JavaFX:与多个EasyBind映射绑定的BooleanBindings [英] JavaFX: BooleanBindings in bind with multiple EasyBind maps

查看:112
本文介绍了JavaFX:与多个EasyBind映射绑定的BooleanBindings的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题在> JavaFX:禁用多个TableView中基于其他TableView的行停止.我想提出一个更笼统的话题,其他人也可以从中受益.

This question goes further where JavaFX: Disable multiple rows in TableView based on other TableView stops. I want to generate a more general topic, of which other people could also benefit.

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

I also have the two tableviews. I also want to disable a row in table2 when table1 contains the same object. This is achieved with the code below:

//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;

});

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

Now I only want the row to be disabled when:

  1. 表1中产品的SKU也在表2中(现在有效)
  2. 表2中的产品数量为负

我不知道如何检查金额,因为我需要与特定SKU相关的金额.如何在一个BooleanBinding中使用多个映射创建此对象?

I do not know how to check on the amount, because I need the amount that is associated with the certain SKU. How can I create this with multiple maps in one BooleanBinding?

任何帮助将不胜感激!

推荐答案

在我看来,您可能会从重新考虑对象模型中受益.看来您的Product有两个不同的值,您称为amount:一个显示在表1中,一个显示在表2中.如果您将Product类的这两个字段设为不同,那么所有这些将变得更加容易,因为您可以使用相同的实际对象(只是在列中显示的属性不同)来表示两个表中的项目.然后,禁用行的条件就只是您正在查看的对象的功能(连同table2.getItems().contains(...)一样).

This sounds to me that you might benefit from reconsidering your object model. It seems that your Product has two different values you refer to as amount: one that's displayed in table1, and one that's displayed in table2. If you make those two different fields of the Product class, then all this becomes much easier, as you can represent the items in both tables with the same actual objects (just with different properties displayed in the columns); and then the criteria for disabling a row becomes just a function of the object you're looking at (along with 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>,列中的单元格值工厂只是查看正确产品的属性.这样,table1的行工厂中的row.getItem()返回SKU对象,并可以根据需要查看table2属性.

Then both tables can be TableView<SKU>s with the cell value factories on the columns just looking at the properties from the correct product. That way row.getItem() in table1's row factory returns the SKU object, and can look at the table2 properties as needed.

如果您确实无法做到这一点,那么执行此操作的一种方法是维持ObservableMap<String, Double>,该ObservableMap<String, Double>会将SKU映射到表2中显示的数量.这需要一些工作,但还算不错:

If you really can't do that, then one way to do this would be to maintain an ObservableMap<String, Double> which maps SKUs to the amount displayed in table2. This is a bit of work, but not too bad:

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

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

Now you need to keep the map updated when the table contents change:

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

然后禁用标准可以是类似的

And then the disable criteria can be something like

row.disableProperty().bind(Bindings.createBooleanBinding(
    () -> row.getItem() != null &&
          skuAmountLookup.containsKey(row.getItem().getSKU()) &&
          skuAmountLookup.get(row.getItem().getSKU()) < 0, 
    skuAmountLookup,
    row.itemProperty()));

我还没有尝试过任何方法,但是应该可以.这里有两个假设:

I haven't tried any of this, but it should work. There are two assumptions here:

  1. SKU在表2中是唯一的
  2. 表2中的金额将保持不变,除了被添加或从表中删除的项目外.如果需要,可以解决此问题,但是它会使table2的项的侦听器增加一层复杂性.

这篇关于JavaFX:与多个EasyBind映射绑定的BooleanBindings的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆