代码之家  ›  专栏  ›  技术社区  ›  Toni_Entranced

自动更新嵌套项的TreeView

  •  0
  • Toni_Entranced  · 技术社区  · 12 年前

    我有一个目标,它有一系列目标。目标有一系列策略。战略有一系列战术。战术有一系列任务。

    我希望能够在TreeView中显示它,并且希望树与项目同步。也就是说,如果我删除了一个Objective,该Objective及其子对象也将从TreeView中消失。

    到目前为止,这是我一直在尝试的。

    /**
     * The base class for all PlanItems, which include ActionItems down to
     * ActionTasks, and Objectives down to Tasks.
     *
     * @author Toni-Tran
     */
    public class PlanItem implements Comparable<PlanItem> {
        protected ObservableList<PlanItem> childPlanItems = FXCollections
                .observableArrayList();
        protected TreeItem<PlanItem> treeItem = new TreeItem<>(this);
    

    这是所有这些项的基类。在其构造函数中:

    public PlanItem() {
        CustomBinding.bindLists(treeItem.getChildren(), childPlanItems, PlanItem::getTreeItem);
    }
    

    我正在使用自定义绑定,它将两个不同对象的列表绑定在一起。(或者,我可以使用EasyBind)。

    /**
     * Binds a source list's elements to a destination list. Any changes made in
     * the source list will reflect in the destination list.
     *
     * @param <SRC> The source list's object type.
     * @param <DEST> The destination list's object type.
     * @param dest The destination list that will be bound to the src list.
     * @param src The source list to watch for changes, and propagate up to the
     * destination list.
     * @param transformer A function that will transform a source list data
     * type, A, into a destination list data type, B.
     */
    public static <SRC extends Object, DEST extends Object> void bindLists(
            ObservableList<DEST> dest, ObservableList<SRC> src, Function<SRC, DEST> transformer) {
        /*Add the initial data into the destination list.*/
        for (SRC a : src) {
            dest.add(transformer.apply(a));
        }
        /*Watch for future data to add to the destination list. Also watch for removal
         of data form the source list to remove its respective item in the destination
         list.*/
        src.addListener((ListChangeListener.Change<? extends SRC> c) -> {
            while (c.next()) {
                /*Watch for removed data.*/
                if (c.wasRemoved()) {
                    for (SRC a : c.getRemoved()) {
                        int from = c.getFrom();
                        dest.remove(from);
                    }
                }
                /*Watch for added data.*/
                if (c.wasAdded()) {
                    for (SRC a : c.getAddedSubList()) {
                        int indexAdded = src.indexOf(a);
                        dest.add(indexAdded, transformer.apply(a));
                    }
                }
            }
        });
    }
    

    我不确定这是否是正确的方法。子项列表通常是扩展PlanItem的对象列表,而不仅仅是PlanItem本身。这不应该是一个 ObservableList<? extends PlanItem> 然后这样做会使我的其余代码变得复杂。

    计划是创建一个包装PlanItem的TreeItem。然后,将TreeItem的子TreeItems与PlanItem的子PlanItems同步。这对每个嵌套的PlanItem也递归重复。

    1 回复  |  直到 12 年前
        1
  •  1
  •   James_D    12 年前

    你的 bindLists 方法是非常通用的,可以在编写时(正如您现在所拥有的那样)不引用您当前正在使用的列表(即不引用 PlanItem 类)。所以我可能会成功

    public static <SRC, DEST> void bindLists(ObservableList<DEST> dest, ObservableList<SRC> src, ...) { ... }
    

    注意,映射函数只需要能够应用于 src (因此,它必须对其元素 钢筋混凝土 是一种类型),并产生可以放入 dest 列表所以使用 Function<SRC, DEST> 可能限制性太强。尝试

    public static <SRC, DEST> void bindLists(ObservableList<DEST> dest, ObservableList<SRC> src, 
         Function<? super SRC, ? extends DEST> transformer) { ... }
    

    现在你可以打电话了

    bindLists(ObservableList<TreeItem<PlanItem>>, ObservableList<T>, PlanItem::getTreeItem)
    

    哪里 T 是 计划项目 或任何子类 ,并且应该易于使用。