JavaFX filteredlist, which filters based on the properties of the items in the list
I have a case where I need to filter an observablelist < item > based on some attributes of the item (that is, the condition is internal rather than external) I found @ L_ 403_ 0@fx There was a filteredlist, so I tried it I can set predicates and filter work until it is determined that the filtered attribute value changes The set predicate is now complete as follows:
list.setPredicate(t -> !t.filteredproperty().get())
Since the predicate returns Boolean instead of Boolean property, changes to this property are not reflected in the list
Is there any simple solution? I can try to do some solutions, such as creating a separate list and synchronizing, or resetting the predicate every time the property changes in a project, hoping to trigger the filtering again, but first of all, if someone knows a beautiful solution, because these alternatives are certainly not
Solution
Create a base list using extractor This causes the base list to trigger an update event when the filteredproperty () of any element changes Filteredlist will observe these events and will update accordingly:
ObservableList<Item> baseList = FXCollections.observableArrayList(item -> new Observable[] {item.filteredproperty()}); FilteredList<Item> list = new FilteredList<>(baseList,t -> ! t.filteredproperty().get());
Quick demo:
import java.util.stream.IntStream; import javafx.beans.Observable; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.Listchangelistener.Change; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; public class DynamicFilteredListTest { public static void main(String[] args) { ObservableList<Item> baseList = FXCollections.observableArrayList(item -> new Observable[] {item.filteredproperty()}); FilteredList<Item> list = new FilteredList<>(baseList,t -> ! t.isFiltered()); list.addListener((Change<? extends Item> c) -> { while (c.next()) { if (c.wasAdded()) { System.out.println(c.getAddedSubList()+ " added to filtered list"); } if (c.wasRemoved()) { System.out.println(c.getRemoved()+ " removed from filtered list"); } } }); System.out.println("Adding ten items to base list:\n"); IntStream.rangeClosed(1,10).mapToObj(i -> new Item("Item "+i)).forEach(baseList::add); System.out.println("\nFiltered list Now:\n"+list); System.out.println("\nSetting filtered flag for alternate items in base list:\n"); IntStream.range(0,5).map(i -> 2*i).mapToObj(baseList::get).forEach(i -> i.setFiltered(true)); System.out.println("\nFiltered list Now:\n"+list); } public static class Item { private final StringProperty name = new SimpleStringproperty() ; private final BooleanProperty filtered = new SimpleBooleanproperty() ; public Item(String name) { setName(name); } public final StringProperty nameproperty() { return this.name; } public final String getName() { return this.nameproperty().get(); } public final void setName(final String name) { this.nameproperty().set(name); } public final BooleanProperty filteredproperty() { return this.filtered; } public final boolean isFiltered() { return this.filteredproperty().get(); } public final void setFiltered(final boolean filtered) { this.filteredproperty().set(filtered); } @Override public String toString() { return getName(); } } }