在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);
}
}