我有一个TreeView,其中有几个节点有CheckBoxes(参见MWE)。
折叠/展开某个节点时,会检查或取消选中其他节点的CheckBox。
要重现行为,只需展开所有节点,检查ChildA
,折叠Block1
,系统会自动检查ChildC
。
package treeviewexample;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.CheckBoxTreeCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TreeViewExample extends Application {
@Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
/* example Treeview */
TreeView tw = new TreeView();
TreeItem rootNode = new TreeItem("Root");
TreeItem blockOne = new TreeItem("Block1");
TreeItem childA = new TreeItem("ChildA");
TreeItem childB = new TreeItem("ChildB");
blockOne.getChildren().add(childA);
blockOne.getChildren().add(childB);
TreeItem blockTwo = new TreeItem("Block2");
TreeItem childC = new TreeItem("ChildC");
TreeItem childD = new TreeItem("ChildD");
blockTwo.getChildren().add(childC);
blockTwo.getChildren().add(childD);
rootNode.getChildren().add(blockOne);
rootNode.getChildren().add(blockTwo);
tw.setRoot(rootNode);
/* add CheckBoxes */
tw.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
root.getChildren().add(tw);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
如何防止此行为?在我的程序的稍后阶段,我想通过TreeView并获取节点的状态(已检查或未检查)以使用它们。
来自https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TreeCell.html我知道以下内容:
由于TreeCell从IndexedCell扩展,每个TreeCell还提供索引属性。索引将在单元格展开和折叠时更新,因此应被视为视图索引而不是模型索引。
这是预期的行为吗?为什么有人想要那个?
答案 0 :(得分:0)
您看到的行为与单元格的索引无关,而仅仅是因为您没有为CheckBoxTreeCell
提供任何机制来“知道”是否应该检查它。因此,当您展开或折叠树中的节点,并且单元格被重用于其他项目时,即使它们现在应该代表新数据,它们也可能会保持其已检查状态。
此处的基本问题是CheckBoxTreeCell
只是视图:它不会保持所选状态。您需要为单元格提供一种机制,以了解它所代表的项目是否被选中。 API提供了两种方法:使用CheckBoxTreeItem
作为树中的项,或者使用具有BooleanProperty
的模型类,并提供该布尔属性的映射。
第一个版本看起来像这样(我也摆脱了所有的原始类型:你真的不应该在这里发布产生警告的代码而只是忽略它们):
public void start(Stage primaryStage) {
StackPane root = new StackPane();
/* example Treeview */
TreeView<String> tw = new TreeView<>();
CheckBoxTreeItem<String> rootNode = new CheckBoxTreeItem<>("Root");
CheckBoxTreeItem<String> blockOne = new CheckBoxTreeItem<>("Block1");
CheckBoxTreeItem<String> childA = new CheckBoxTreeItem<>("ChildA");
CheckBoxTreeItem<String> childB = new CheckBoxTreeItem<>("ChildB");
blockOne.getChildren().add(childA);
blockOne.getChildren().add(childB);
CheckBoxTreeItem<String> blockTwo = new CheckBoxTreeItem<>("Block2");
CheckBoxTreeItem<String> childC = new CheckBoxTreeItem<>("ChildC");
CheckBoxTreeItem<String> childD = new CheckBoxTreeItem<>("ChildD");
blockTwo.getChildren().add(childC);
blockTwo.getChildren().add(childD);
rootNode.getChildren().add(blockOne);
rootNode.getChildren().add(blockTwo);
tw.setRoot(rootNode);
/* add CheckBoxes */
tw.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
root.getChildren().add(tw);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
第二个选项如下:
@Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
/* example Treeview */
TreeView<Item> tw = new TreeView<>();
CheckBoxTreeItem<Item> rootNode = new CheckBoxTreeItem<>(new Item("Root"));
CheckBoxTreeItem<Item> blockOne = new CheckBoxTreeItem<>(new Item("Block1"));
CheckBoxTreeItem<Item> childA = new CheckBoxTreeItem<>(new Item("ChildA"));
CheckBoxTreeItem<Item> childB = new CheckBoxTreeItem<>(new Item("ChildB"));
blockOne.getChildren().add(childA);
blockOne.getChildren().add(childB);
CheckBoxTreeItem<Item> blockTwo = new CheckBoxTreeItem<>(new Item("Block2"));
CheckBoxTreeItem<Item> childC = new CheckBoxTreeItem<>(new Item("ChildC"));
CheckBoxTreeItem<Item> childD = new CheckBoxTreeItem<>(new Item("ChildD"));
blockTwo.getChildren().add(childC);
blockTwo.getChildren().add(childD);
rootNode.getChildren().add(blockOne);
rootNode.getChildren().add(blockTwo);
tw.setRoot(rootNode);
StringConverter<TreeItem<Item>> itemStringConverter = new StringConverter<TreeItem<Item>>() {
@Override
public String toString(TreeItem<Item> item) {
return item.getValue().getName();
}
@Override
public TreeItem<Item> fromString(String string) {
return new TreeItem<>(new Item(string));
}
};
/* add CheckBoxes */
tw.setCellFactory(
CheckBoxTreeCell.forTreeView(treeItem -> treeItem.getValue().selectedProperty(), itemStringConverter));
root.getChildren().add(tw);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Item {
private final String name;
// use something with a more meaningful name here:
private final BooleanProperty selected = new SimpleBooleanProperty();
public Item(String name, boolean selected) {
this.name = name;
setSelected(selected);
}
public Item(String name) {
this(name, false);
}
public String getName() {
return name;
}
public BooleanProperty selectedProperty() {
return selected;
}
public final boolean isSelected() {
return selectedProperty().get();
}
public final void setSelected(boolean selected) {
selectedProperty().set(selected);
}
}