我有一个最大深度为2的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);
}
}
});
启用多选模式。
任何帮助表示感谢。
答案 0 :(得分:2)
在JavaFX中,在处理对该列表的现有更改时,不允许更改ObservableList
。 (这是否是一个明智的规则是开放的辩论,然而,这是一个规则。)
选择模型保留所选索引和所选项目的ObservableList
个。处理这些列表中的更改的部分原因是在所选项和所选索引上调用侦听器。因此,您无法从选择器本身的侦听器更改选择。
&#34;适当&#34;这样做的方法是提供自己的选择模型实现。这有点痛苦,因为有很多方法要实现,并且它们的使用没有很好地记录。这是一个例子,虽然这是一个起点,并不打算成为生产质量:
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);
}
}