Is it possible to hide a node in a tree View (the same way it works for Root) without having to remove the node from the tree itself ? The aim is to be able to provide a filter and a "show/hide" option on certain item of the tree.
All help appreciated
Thanks
I found this article by Christoph Keimel which I think should solve your problem.
Basically you can't do it without a hack. You can have a FilterableTreeItem which extends TreeItem in which you create a FilteredList.
public class FilterableTreeItem<T> extends TreeItem<T> {
private final ObservableList<TreeItem<T>> sourceList;
private final ObjectProperty<TreeItemPredicate<T>> predicate = new SimpleObjectProperty<>();
public FilterableTreeItem(T value) {
super(value);
sourceList = FXCollections.observableArrayList();
FilteredList<TreeItem<T>> filteredList = new FilteredList<>(sourceList);
filteredList.predicateProperty().bind(Bindings.createObjectBinding(() -> {
return child -> {
// Set the predicate of child items to force filtering
if (child instanceof FilterableTreeItem) {
FilterableTreeItem<T> filterableChild = (FilterableTreeItem<T>) child;
filterableChild.setPredicate(predicate.get());
}
// If there is no predicate, keep this tree item
if (predicate.get() == null) {
return true;
}
// If there are children, keep this tree item
if (!child.getChildren().isEmpty()) {
return true;
}
// Otherwise ask the TreeItemPredicate
return predicate.get().test(this, child.getValue());
};
}, predicate));
setHiddenFieldChildren(filteredList);
}
/**
* Set the hidden private field {@link TreeItem#children} through reflection and hook the hidden {@link ListChangeListener} in {@link TreeItem#childrenListener} to the list
*
*/
protected void setHiddenFieldChildren(ObservableList<TreeItem<T>> list) {
Field children = ReflectionUtils.findField(getClass(), "children");
children.setAccessible(true);
ReflectionUtils.setField(children, this, list);
Field childrenListener1 = ReflectionUtils.findField(getClass(), "childrenListener");
childrenListener1.setAccessible(true);
Object childrenListener = ReflectionUtils.getField(childrenListener1, this);
list.addListener((ListChangeListener<? super TreeItem<T>>) childrenListener);
}
/**
* Returns the list of children that is backing the filtered list.
*
* @return underlying list of children
*/
public ObservableList<TreeItem<T>> getInternalChildren() {
return sourceList;
}
public final ObjectProperty<TreeItemPredicate<T>> predicateProperty() {
return predicate;
}
public final TreeItemPredicate<T> getPredicate() {
return predicate.get();
}
public final void setPredicate(TreeItemPredicate<T> predicate) {
this.predicate.set(predicate);
}
}
You will also need the TreeItemPredicate
@FunctionalInterface
public interface TreeItemPredicate<T> {
/**
* Utility method to create a TreeItemPredicate from a given {@link Predicate}
*/
static <T> TreeItemPredicate<T> create(Predicate<T> predicate) {
return (parent, value) -> predicate.test(value);
}
/**
* Evaluates this predicate on the given argument.
*
* @param parent
* the parent tree item of the element or null if there is no
* parent
* @param value
* the value to be tested
* @return {@code true} if the input argument matches the
* predicate,otherwise {@code false}
*/
boolean test(TreeItem<T> parent, T value);
}
And you put it together in your Controller
MyNode myRootNode = myService.getTreeRootNode();
FilterableTreeItem<MyNode> rootItem = new FilterableTreeItem<>(myRootNode);
rootItem.setExpanded(true);
for (MyNode node : myRootNode.getChildren()) {
FilterableTreeItem<MyNode> item = new FilterableTreeItem<>(node);
rootItem.getInternalChildren().add(item);
}
tree.setRoot(rootItem);
rootItem.predicateProperty().bind(Bindings.createObjectBinding(()
-> TreeItemPredicate.<MyNode> create(myNode
-> myNode.isStyled() == hide.getValue())
, hide));
hide is a SimpleBooleanProperty. My node has a boolean property styled.
private final BooleanProperty hide = new SimpleBooleanProperty();
The Code simply allows to hide the stlyed nodes or the not styled ones. I know it is stupid, but I just made a test
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With