2014-09-04 85 views
0

我有一個目標,它有一個目標列表。一個目標有一個策略列表。一個策略有一個策略列表。戰術有一個任務列表。自動更新嵌套項目的TreeView

我希望能夠在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)); 
       } 
      } 
     } 
    }); 
} 

我不確定這是否正確。子項目列表通常是EXTEND PlanItem的對象列表,而不僅僅是PlanItem本身。那該不該是ObservableList<? extends PlanItem>呢?這樣做會使我的其他代碼變得複雜。

該計劃是創建一個包裝PlanItem的TreeItem。然後,將TreeItem的子TreeItems同步到PlanItem的子PlanItems。這也對每個嵌套的PlanItem遞歸地重複。

回答

1

你的bindLists方法是相當一般的,並且可以在沒有任何參考你正在使用的列表(即沒有參考PlanItem類)的情況下編寫(現在你已經有了)。所以,我很可能只是讓

public static <SRC, DEST> void bindLists(ObservableList<DEST> dest, ObservableList<SRC> 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) 

其中TPlanItem或任何子類,它應該很容易使用。

+0

爲什麼我必須給函數參數一個下限?爲什麼不擴展? – 2014-09-04 19:20:01

+0

你實際上想要傳入的函數是一個'Function (因爲你在'PlanItem'類中定義了它,並且使用'this - > new TreeItem <>(...)'。 )如果這是作用於一個元素,比如說'ObservableList ',那麼函數的參數類型('PlanItem')就是你給它的實際值的超類('Goal')...元素列表必須是*可分配給*函數的類型。函數的返回類型必須*分配給目標列表的類型,所以你在那裏使用'extends'。 – 2014-09-04 19:54:12

+0

'功能<?超級SRC,?擴展DEST>'。我理解該函數的第二個參數。我們試圖將'DEST'(和'DEST'的子類)對象插入'List '中。但是我仍然對第一個參數感到困惑。來源清單可以是「清單」或「清單」或其他。現在的'SRC'的這兩個超類是如何?我很抱歉,如果我看起來很愚蠢,我只是在泛型界限上很糟糕。 :( – 2014-09-05 00:21:37