我的情况是显示TreeView,有两个级别的条目(父母和孩子),如下所示:
root (invisible)
|_ parent item 1
|_ child item 1-1
|_ child item 1-2
|_ parent item 2
|_ child item 2-1
这些项目都是标准的CheckBoxTreeItem
。根据某些功能,我想要做的是按住CTRL键点击parent item
的复选框,选择一组孩子。例如,在这里我可能只想在CTRL单击父复选框时选择每个子列表中的第一个子项(即child item 1-1
和child item 2-1
)。
这可能吗?据我所见,没有好办法可以访问复选框并提供例如一个onMouseClick事件处理程序,这是对我有意义的解决方案。
上面给出的示例树布局的代码:
TreeViewTest.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.CheckBoxTreeCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TreeViewTest extends Application {
@Override
public void start(final Stage stage) {
StackPane sceneRoot = new StackPane();
// create the tree model
CheckBoxTreeItem<String> parent1 = new CheckBoxTreeItem<>("parent 1");
CheckBoxTreeItem<String> parent2 = new CheckBoxTreeItem<>("parent 2");
CheckBoxTreeItem<String> child1_1 = new CheckBoxTreeItem<>("child 1-1");
CheckBoxTreeItem<String> child1_2 = new CheckBoxTreeItem<>("child 1-2");
CheckBoxTreeItem<String> child2_1 = new CheckBoxTreeItem<>("child 2-1");
CheckBoxTreeItem<String> root = new CheckBoxTreeItem<>("root");
// attach the nodes
parent1.getChildren().addAll(child1_1, child1_2);
parent2.getChildren().addAll(child2_1);
root.getChildren().addAll(parent1, parent2);
// display everything
root.setExpanded(true);
parent1.setExpanded(true);
parent2.setExpanded(true);
// create the treeView
final TreeView<String> treeView = new TreeView<>();
treeView.setShowRoot(false);
treeView.setRoot(root);
// set the cell factory
treeView.setCellFactory(CheckBoxTreeCell.forTreeView());
// display the tree
sceneRoot.getChildren().addAll(treeView);
Scene scene = new Scene(sceneRoot, 200, 200);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Main.launch(args);
}
}
答案 0 :(得分:1)
您需要-std=c++11
的自定义实现。这应该为您提供一个起点,允许您实现所需的其他功能:
TreeCell
答案 1 :(得分:0)
正如@James_D在该问题的评论中所建议的,一种解决方案是创建一个公开CheckBox的自定义TreeCell实现。
修改后的TreeViewTest.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeView;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TreeViewTest extends Application {
@Override
public void start(final Stage stage) {
StackPane sceneRoot = new StackPane();
// create the tree model
CheckBoxTreeItem<String> parent1 = new CheckBoxTreeItem<>("parent 1");
CheckBoxTreeItem<String> parent2 = new CheckBoxTreeItem<>("parent 2");
CheckBoxTreeItem<String> child1_1 = new CheckBoxTreeItem<>("child 1-1");
CheckBoxTreeItem<String> child1_2 = new CheckBoxTreeItem<>("child 1-2");
CheckBoxTreeItem<String> child2_1 = new CheckBoxTreeItem<>("child 2-1");
CheckBoxTreeItem<String> root = new CheckBoxTreeItem<>("root");
// attach the nodes
parent1.getChildren().addAll(child1_1, child1_2);
parent2.getChildren().addAll(child2_1);
root.getChildren().addAll(parent1, parent2);
// display everything
root.setExpanded(true);
parent1.setExpanded(true);
parent2.setExpanded(true);
// create the treeView
final TreeView<String> treeView = new TreeView<>();
treeView.setShowRoot(false);
treeView.setRoot(root);
// set the cell factory UPDATED
treeView.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>() {
@Override
public TreeCell<String> call(TreeView<String> param) {
TreeCell<String> cell = new MyTreeCell<>();
((MyTreeCell) cell).getCheckBox().setOnMouseClicked(e -> {
if (!cell.getTreeItem().isLeaf())
if (e.isControlDown() && e.getButton() == MouseButton.PRIMARY)
System.out.println("CTRL-clicked");
});
return cell;
}
});
// display the tree
sceneRoot.getChildren().addAll(treeView);
Scene scene = new Scene(sceneRoot, 200, 200);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Main.launch(args);
}
}
MyTreeCell.java(稍微调整从CheckBoxTreeCell复制的代码)
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.CheckBox;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.util.Callback;
import javafx.util.StringConverter;
public class MyTreeCell<T> extends TreeCell<T> {
private final CheckBox checkBox;
private ObservableValue<Boolean> booleanProperty;
private BooleanProperty indeterminateProperty;
public MyTreeCell() {
this.getStyleClass().add("check-box-tree-cell");
this.checkBox = new CheckBox();
this.checkBox.setAllowIndeterminate(false);
// by default the graphic is null until the cell stops being empty
setGraphic(null);
}
// --- checkbox
public final CheckBox getCheckBox() { return checkBox; }
// --- selected state callback property
private ObjectProperty<Callback<TreeItem<T>, ObservableValue<Boolean>>>
selectedStateCallback =
new SimpleObjectProperty<>(
this, "selectedStateCallback");
public final ObjectProperty<Callback<TreeItem<T>, ObservableValue<Boolean>>> selectedStateCallbackProperty() {
return selectedStateCallback;
}
public final void setSelectedStateCallback(Callback<TreeItem<T>, ObservableValue<Boolean>> value) {
selectedStateCallbackProperty().set(value);
}
public final Callback<TreeItem<T>, ObservableValue<Boolean>> getSelectedStateCallback() {
return selectedStateCallbackProperty().get();
}
@Override public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
TreeItem<T> treeItem = getTreeItem();
// update the node content
setText((treeItem == null ? "" : treeItem.getValue().toString()));
checkBox.setGraphic(treeItem == null ? null : treeItem.getGraphic());
setGraphic(checkBox);
// uninstall bindings
if (booleanProperty != null) {
checkBox.selectedProperty().unbindBidirectional((BooleanProperty)booleanProperty);
}
if (indeterminateProperty != null) {
checkBox.indeterminateProperty().unbindBidirectional(indeterminateProperty);
}
// install new bindings.
// We special case things when the TreeItem is a CheckBoxTreeItem
if (treeItem instanceof CheckBoxTreeItem) {
CheckBoxTreeItem<T> cbti = (CheckBoxTreeItem<T>) treeItem;
booleanProperty = cbti.selectedProperty();
checkBox.selectedProperty().bindBidirectional((BooleanProperty)booleanProperty);
indeterminateProperty = cbti.indeterminateProperty();
checkBox.indeterminateProperty().bindBidirectional(indeterminateProperty);
} else {
Callback<TreeItem<T>, ObservableValue<Boolean>> callback = getSelectedStateCallback();
if (callback == null) {
throw new NullPointerException(
"The CheckBoxTreeCell selectedStateCallbackProperty can not be null");
}
booleanProperty = callback.call(treeItem);
if (booleanProperty != null) {
checkBox.selectedProperty().bindBidirectional((BooleanProperty)booleanProperty);
}
}
}
}
}