TreeView Java FX:隐藏节点

时间:2014-11-28 07:02:20

标签: java javafx treeview java-8

是否可以在树视图中隐藏节点(与Root的工作方式相同),而不必从树本身中删除节点?目的是能够在树的某个项目上提供过滤器和“显示/隐藏”选项。

所有帮助表示赞赏

由于

2 个答案:

答案 0 :(得分:4)

我发现Christoph Keimel的这个article,我认为应该解决你的问题。

基本上你没有黑客就无法做到。 您可以使用FilterableTreeItem扩展TreeItem,您可以在其中创建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);
}

}

您还需要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);
}

你把它放在你的控制器

            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是一个SimpleBooleanProperty。我的节点有一个布尔属性样式。

private final BooleanProperty hide = new SimpleBooleanProperty();

代码只允许隐藏明显的节点或没有样式的节点。 我知道这很愚蠢,但我刚做了一个测试

答案 1 :(得分:1)

您无法将单元格visibleProprerty绑定到外部布尔属性,因为VirtualFlow将自行管理单元格,并在需要时将其可见性设置为true,而不管您的设置如何。“ / p>

作为替代方法,您可以禁用单元格,或者通过将其不透明度设置为0来使其不可见,但单元格的大小将存在空白。

这个answer向您展示了如何禁用单个单元格。要更改不透明度,只需向opacityProperty类添加Wrap,或创建绑定:

    // disable cell
        cell.disableProperty().bind(wrap.disabledProperty());

    // or "hide" cell with blank gap
        // - with new property in Wrap
        cell.opacityProperty().bind(wrap.opacityProperty());
        // - with a Binding
        cell.opacityProperty().bind(
            Bindings.createDoubleBinding(()->wrap.disabledProperty().get()?0d:1d,
                    wrap.disabledProperty()));