Reputation: 174
Let's assume I have a simple application written in JavaFX.
It has a TableView with two columns, one with elements' names and other with elements' values.
Now I want compute average value of items that are visible in TableView, and update it every time elements are filtered by name.
This is what I already have:
@FXML
public void filterProducts() {
filteredProducts = new FilteredList<>(FXCollections.observableArrayList(mainApp.getProductList()), p -> true);
filterBtn.setOnMouseClicked(event -> {
filteredProducts.setPredicate(product -> {
return checkFilteringForNetPrice(product) && checkFilteringForManufacturer(product);
});
});
SortedList<Product> sortedProducts = new SortedList<>(filteredProducts);
sortedProducts.comparatorProperty().bind(productTable.comparatorProperty());
productTable.setItems(sortedProducts);
computeAverageAfterFiltering(sortedProducts);
}
With call for computeAverageAfterFiltering(sortedProducts)
method I have been trying to compute average value of sortedProducts
elements, but it contains exactly the same number of elements as mainApp.getProductList()
.
I expected to find only filtered and sorted elements in sortedProducts
.
What is wrong?
Upvotes: 0
Views: 129
Reputation: 209553
You're only applying the filter when the button is pressed; however you are invoking the method computeAverageAfterFiltering
immediately, i.e. before the filter is applied.
You can maintain the average of the elements in the filtered list with a binding:
DoubleBinding average = Bindings.createDoubleBinding(
() -> computeAverage(sortedProducts),
sortedProducts);
The first argument to createDoubleBinding
is the function that evaluates the binding, and the second is a list of objects to observe for changes. In this case we just pass the sorted list, so any time the list contents change, the binding is recomputed.
Then you can do things like
Label averageLabel = new Label();
averageLabel.textProperty().bind(average.asString("Average price: %f"));
with
private double computeAverage(List<Product> products) {
return products.stream()
// adjust Product::getPrice to give the values you want to average:
.collect(Collectors.averagingDouble(Product::getPrice));
}
Upvotes: 1