2015-11-11 101 views
1

我有一個最大深度爲2的TreeTable,例如JavaFX TreeTable在選擇父項時選擇子項並從父項中移除選擇項

  • fooType

    -foo

    -foo

如果我選擇fooType我希望程序自動選擇所有子項,並取消父項。但是當我嘗試這個時,我總是得到一個IndexOutOfBoundsException。

myTreeTable.getSelectionModel().selectedItemProperty().addListener((obs, ov, nv) -> { 
    if (nv.getValue() instanceof fooType) { 
    myTreeTable.getSelectionModel().clearSelection(myTreeTable.getSelectionModel().getSelectedIndex()); 
    if (!nv.isExpanded()) { 
     nv.setExpanded(true); 
    } 
    ObservableList<TreeItem<IfooTreeItem>> children = nv.getChildren(); 
    for (TreeItem<IfooTreeItem> item : children) { 
     annotationsTreeTable.getSelectionModel().select(item); 
    } 
    } 
}); 

啓用多選模式。

任何幫助表示讚賞。

回答

2

在JavaFX中,在處理對該列表的現有更改時,不允許更改ObservableList。 (不管這是否明智的規則可以辯論,但是,這是一條規則。)

選擇模型保持ObservableList同時選擇的索引和選定的項目。處理這些列表中的更改的一部分是調用所選項目和選定索引的偵聽器。因此,您無法從選擇本身的偵聽器中更改選擇。

做到這一點的「正確」方法是提供您自己的選擇模型實現。這有點痛苦,因爲有很多方法可以實現,並且它們的使用沒有很好的記錄。下面是一個例子,雖然這是作爲一個起點,並不打算成爲生產質量:

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 
import java.util.stream.Stream; 

import javafx.application.Application; 
import javafx.collections.ObservableList; 
import javafx.scene.Scene; 
import javafx.scene.control.MultipleSelectionModel; 
import javafx.scene.control.SelectionMode; 
import javafx.scene.control.TreeItem; 
import javafx.scene.control.TreeView; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 

public class TreeSelectionExample extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     TreeView<String> tree = new TreeView<>(); 
     TreeItem<String> root = new TreeItem<>(); 
     tree.setRoot(root); 
     tree.setShowRoot(false); 

     root.getChildren().add(new TreeItem<>("Item 1")); 
     root.getChildren().add(new TreeItem<>("Item 2")); 

     root.getChildren().forEach(item -> 
      Stream.of("A", "B").map(s -> new TreeItem<String>(item.getValue()+s)) 
      .forEach(item.getChildren()::add)); 

     MultipleSelectionModel<TreeItem<String>> defaultSelectionModel = tree.getSelectionModel() ; 
     defaultSelectionModel.setSelectionMode(SelectionMode.MULTIPLE); 

     tree.setSelectionModel(new MultipleSelectionModel<TreeItem<String>>() { 

      { 
       setSelectionMode(SelectionMode.MULTIPLE); 
      } 

      @Override 
      public ObservableList<Integer> getSelectedIndices() { 
       return defaultSelectionModel.getSelectedIndices(); 
      } 

      @Override 
      public ObservableList<TreeItem<String>> getSelectedItems() { 
       return defaultSelectionModel.getSelectedItems(); 
      } 

      @Override 
      public void selectRange(int start, int end) { 
       System.out.println("selectRange("+start+", "+end+")"); 
       List<TreeItem<String>> items = new ArrayList<>(); 
       for (int i = start; i < end; i++) { 
        items.add(tree.getTreeItem(i)); 
       } 
       for (int i = start ; i > end; i--) { 
        items.add(tree.getTreeItem(i)); 
       } 
       items.forEach(this::select); 
      } 

      @Override 
      public void selectIndices(int index, int... indices) { 
       System.out.println("select("+index+", "+Arrays.toString(indices)+")"); 
       TreeItem<String> item = tree.getTreeItem(index); 
       if (item.isLeaf()) { 
        defaultSelectionModel.select(item);; 
       } else { 
        List<TreeItem<String>> leaves = new ArrayList<>(); 
        findLeavesAndExpand(item, leaves); 
        for (TreeItem<String> leaf : leaves) { 
         defaultSelectionModel.select(leaf); 
        } 
       } 
       for (int i : indices) { 
        item = tree.getTreeItem(i); 
        if (item.isLeaf()) { 
         defaultSelectionModel.select(item);;       
        } else { 
         List<TreeItem<String>> leaves = new ArrayList<>(); 
         findLeavesAndExpand(item, leaves); 
         for (TreeItem<String> leaf : leaves) { 
          defaultSelectionModel.select(leaf); 
         } 
        } 
       } 
      } 

      @Override 
      public void selectAll() { 
       System.out.println("selectAll()"); 
       List<TreeItem<String>> leaves = new ArrayList<>(); 
       findLeavesAndExpand(tree.getRoot(), leaves); 
       for (TreeItem<String> leaf : leaves) { 
        defaultSelectionModel.select(leaf); 
       } 
      } 

      @Override 
      public void selectFirst() { 
       System.out.println("selectFirst()"); 
       TreeItem<String> firstLeaf ; 
       for (firstLeaf = tree.getRoot(); ! firstLeaf.isLeaf(); firstLeaf = firstLeaf.getChildren().get(0)) ; 
       defaultSelectionModel.select(firstLeaf); 
      } 

      @Override 
      public void selectLast() { 
       System.out.println("selectLast()"); 
       TreeItem<String> lastLeaf ; 
       for (lastLeaf = tree.getRoot(); ! lastLeaf.isLeaf(); 
         lastLeaf = lastLeaf.getChildren().get(lastLeaf.getChildren().size()-1)) ; 
       defaultSelectionModel.select(lastLeaf); 
      } 

      @Override 
      public void clearAndSelect(int index) { 
       TreeItem<String> item = tree.getTreeItem(index); 
       defaultSelectionModel.clearSelection(); 
       if (item.isLeaf()) { 
        defaultSelectionModel.select(item); 
       } else { 
        List<TreeItem<String>> leaves = new ArrayList<>(); 
        findLeavesAndExpand(item, leaves); 
        for (TreeItem<String> leaf : leaves) { 
         defaultSelectionModel.select(leaf); 
        } 
       } 
      } 

      @Override 
      public void select(int index) { 
       System.out.println("select("+index+")"); 
       select(tree.getTreeItem(index)); 
      } 

      @Override 
      public void select(TreeItem<String> item) { 
       System.out.println("select("+item.getValue()+")"); 
       if (item.isLeaf()) { 
        defaultSelectionModel.select(item); 
       } else { 
        List<TreeItem<String>> leaves = new ArrayList<>(); 
        findLeavesAndExpand(item, leaves); 
        for (TreeItem<String> leaf : leaves) { 
         defaultSelectionModel.select(leaf); 
        }      
       } 
      } 

      @Override 
      public void clearSelection(int index) { 
       defaultSelectionModel.clearSelection(index); 
      } 

      @Override 
      public void clearSelection() { 
       defaultSelectionModel.clearSelection(); 
      } 

      @Override 
      public boolean isSelected(int index) { 
       return defaultSelectionModel.isSelected(index); 
      } 

      @Override 
      public boolean isEmpty() { 
       return defaultSelectionModel.isEmpty(); 
      } 

      @Override 
      public void selectPrevious() { 
       // TODO Auto-generated method stub 
       // not sure on implementation needed here 
      } 

      @Override 
      public void selectNext() { 
       System.out.println("selectNext()"); 
       // TODO Auto-generated method stub 
       // not sure on implementation needed here 
      } 

      private void findLeavesAndExpand(TreeItem<String> node, List<TreeItem<String>> leaves) { 
       if (node.isLeaf()) { 
        leaves.add(node); 
       } else { 
        node.setExpanded(true); 
        for (TreeItem<String> child : node.getChildren()) { 
         findLeavesAndExpand(child, leaves); 
        } 
       } 
      } 

     }); 

     primaryStage.setScene(new Scene(new BorderPane(tree), 400, 400)); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
}