JavaFX TreeTable select 子级,当父级被 selected 并从父级移除 selection
JavaFX TreeTable select children when parent is selected and remove selection from parent
我有一个最大深度为 2 的 TreeTable,例如
fooType
-foo
-foo
如果我 select fooType 我希望程序自动 select 所有子项并删除 select 父项。但是当我尝试这个时,我总是得到一个 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);
}
}
});
多select离子模式已启用。
感谢任何帮助。
在 JavaFX 中,您不能在处理该列表的现有更改时更改 ObservableList
。 (这是否是一个明智的规则有待商榷,但它是一个规则。)
选择模型保留 ObservableList
所选索引和所选项目。这些列表中更改的部分处理是调用所选项目和所选索引的侦听器。因此,您不能从选择本身的侦听器更改选择。
执行此操作的 "proper" 方法是提供您自己的选择模型实现。这有点麻烦,因为有很多方法要实现,而且它们的使用没有很好的记录。这是一个示例,尽管这是一个起点而不是生产质量:
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);
}
}
我有一个最大深度为 2 的 TreeTable,例如
fooType
-foo
-foo
如果我 select fooType 我希望程序自动 select 所有子项并删除 select 父项。但是当我尝试这个时,我总是得到一个 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);
}
}
});
多select离子模式已启用。
感谢任何帮助。
在 JavaFX 中,您不能在处理该列表的现有更改时更改 ObservableList
。 (这是否是一个明智的规则有待商榷,但它是一个规则。)
选择模型保留 ObservableList
所选索引和所选项目。这些列表中更改的部分处理是调用所选项目和所选索引的侦听器。因此,您不能从选择本身的侦听器更改选择。
执行此操作的 "proper" 方法是提供您自己的选择模型实现。这有点麻烦,因为有很多方法要实现,而且它们的使用没有很好的记录。这是一个示例,尽管这是一个起点而不是生产质量:
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);
}
}