JavaFX: BooleanBindings combined with multiple EasyBind cards

This question goes further, where is JavaFX: disconnecting multiple rows in a TableView based on another TableView stops. I want to create a more general topic that other people could use.

I also have two tables. I also want to disable the row in table2 when table1 contains the same object. This is achieved using 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 want the string to be disabled when:

  • The SKU of the product from table 1 is also in table 2 (now it works)
  • The sum of the product in table 2 is negative.

I do not know how to check the amount, because I need the amount associated with a specific SKU. How can I create this with multiple cards in one BooleanBinding?

Any help is much appreciated!

+1
javafx javafx-8
source share
1 answer

It seems to me that you may need to reconsider your object model. It seems that your Product has two different values ​​that you name amount : the one that appears in table1, and the one that appears in table2. If you create these two different fields of the Product class, all this will become much simpler, since you can represent elements in both tables with the same actual objects (only with different properties displayed in the columns); and then the criteria for disconnecting a row becomes only a function of the object you are looking at (along with table2.getItems().contains(...) ).

Another option might be the SKU class:

 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... } 

Then both tables can be a TableView<SKU> with factories of cell values ​​in columns, just looking at the properties from the correct product. Thus, row.getItem() in table1, the row factory returns an SKU object and can, if necessary, look for the properties of table2.

If you really cannot do this, then one way to do this is to support ObservableMap<String, Double> , which maps the SKU to the amount displayed in table2. This is a little work, but not so 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 update the map when changing the contents of the table:

 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 pretty inefficient though, the following will just update what 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 disconnection criteria may be similar to

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

I have not tried any of this, but it should work. There are two assumptions here:

  • SKUs are unique in table 2
  • The amount in table 2 will not change, except by adding or removing items from the table. If necessary, this can be processed, but adds another level of complexity to the listener on table2 elements.
+1
source share

All Articles