在找到CheckBoxTreeItem之前,我使用了一个带有ComboBox的常规TreeItem。 CellFactory有一个onAction属性,我将其传递给CheckBox onAction方法。 onAction EventHandler来自Controller,所以当我选中/取消选中控制器中的操作方法时,调用它。问题是TreeItem没有被选中。
现在尝试使用CheckBoxTreeItem。但是我在选择和行动方面遇到了一些问题。
我需要在选中/取消选中CheckBox时执行操作。我希望复选框在选择TreeItem时更改状态。我需要在更改CheckBox时选择TreeItem。
1) 选择TreeItem不会更改CheckBox的选定状态。我不得不写一个onMousePressed动作来做到这一点。
@FXML public void performSelection() {
TreeItem<Mine> selectedItem = treeView.getSelectionModel().getSelectedItem();
boolean selected = ((CheckBoxTreeItem<Mine>) selectedItem).isSelected();
((CheckBoxTreeItem<Mine>) selectedItem).setSelected(!selected);
}
但是,当选中/取消选中TreeItem上的CheckBox时,不会选择该TreeItem。这不是CheckBoxTreeItem的意思吗?
2) 我创建了一个ChangeListener,它监听CheckBoxTreeItem selectedProperty的状态。此侦听器在树中的每个项目上注册。这是我可以创建一个动作来检查/取消选中的唯一方法。
但是,检查TreeItem,因为它没有选择TreeItem,我无法使用监听器中的tree.getSelectionModel()。getSelectedItem()访问它。我无法访问CheckBox项目的TreeItem数据的CheckBox操作毫无意义。如果我选择一个TreeItem,它将保留在该TreeItem上,如果我检查另一个TreeItem CheckBox,则selectedItem是错误的。
如果我选择顶部项目并且我想对该项目数据执行某些操作,则会为所有子项调用更改侦听器。这使问题复杂化。我只关心选中/未选中的所选TreeItem的状态。
没有比注册ChangeListener更好的方法来向CheckBoxTreeItem添加操作吗?
第3) 如果没有其他兄弟姐妹,取消选中该子项将取消选中父级。我不希望这样。但是,如果未选中父级,我希望孩子们“离开”/取消选中,但我不想收到通知。如果我取消选中并且有孩子,则所有孩子都应该取消选中。但是,我对未检查项目的子项目的更改事件并不感兴趣。我的问题仍然是下面的所有项目都会触发更改事件,而不仅仅是我感兴趣的项目。
我可以将每个TreeItem设置为独立的。然后在未选中时折叠展开的项目。孩子们的状态仍然独立于其父母已检查或未选中,但不会显示。
问题1是我遇到的最重要的问题。检查CheckBox需要选择该CheckBox的TreeItem。
问题2适用于ChangeListener,虽然我希望有更好的选择,并且可以通过将所有项目设置为独立来避免此处的问题。
问题3我也可以通过将所有项目设置为独立来避开,并在取消选中父项时隐藏它们。他们仍然保持着自己的状态,但是看不见了。
小型测试应用程序
package com.company;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class MineAppTest extends Application {
private TreeView<Mine> treeView;
private MineChangeListener mineChangeListener = new MineChangeListener();
public static void main(String[] argv) {
MineAppTest.launch();
}
/* (non-Javadoc)
* @see javafx.application.Application#start(javafx.stage.Stage)
*/
@Override
public void start(Stage primaryStage) throws Exception {
GridPane contentPane = new GridPane();
contentPane.getChildren().add(new Text("Hello World!"));
treeView = new TreeView<>();
treeView.setCellFactory(new MineTreeCellFactory());
treeView.setOnMousePressed(event -> {
TreeItem<Mine> selectedItem = treeView.getSelectionModel().getSelectedItem();
boolean selected = ((CheckBoxTreeItem<Mine>)selectedItem).isSelected();
((CheckBoxTreeItem<Mine>)selectedItem).setSelected(!selected);
selectedItem.setExpanded(!selected);
});
treeView.setShowRoot(false);
Mine mine1 = new Mine("mine", true);
CheckBoxTreeItem<Mine> rootItem = new CheckBoxTreeItem<>(mine1, null, true);
rootItem.setExpanded(true);
treeView.setRoot(rootItem);
Mine mine2 = new Mine("test1", true);
CheckBoxTreeItem<Mine> item1Level1 = new CheckBoxTreeItem<>(mine2, null, mine2.isEnabled());
item1Level1.setExpanded(true);
//item1Level1.setIndependent(true);
item1Level1.selectedProperty().addListener(mineChangeListener);
rootItem.getChildren().add(item1Level1);
Mine mine3 = new Mine("subtest1", true);
CheckBoxTreeItem<Mine> item1Level2 = new CheckBoxTreeItem<>(mine3, null, mine3.isEnabled());
item1Level2.setExpanded(true);
//item1Level2.setIndependent(true);
item1Level2.selectedProperty().addListener(mineChangeListener);
item1Level1.getChildren().add(item1Level2);
Mine mine4 = new Mine("subtest2", true);
CheckBoxTreeItem<Mine> item2Level2 = new CheckBoxTreeItem<>(mine4, null, mine4.isEnabled());
item2Level2.setExpanded(true);
//item2Level2.setIndependent(true);
item2Level2.selectedProperty().addListener(mineChangeListener);
item1Level1.getChildren().add(item2Level2);
Mine mine5 = new Mine("test2", true);
CheckBoxTreeItem<Mine> item2Level1 = new CheckBoxTreeItem<>(mine5, null, mine5.isEnabled());
item2Level1.setExpanded(true);
//item2Level1.setIndependent(true);
item2Level1.selectedProperty().addListener(mineChangeListener);
item1Level1.getChildren().add(item2Level1);
Mine mine6 = new Mine("subtest2", true);
CheckBoxTreeItem<Mine> item4Level2 = new CheckBoxTreeItem<>(mine6, null, mine6.isEnabled());
item4Level2.setExpanded(true);
//item4Level2.setIndependent(true);
item4Level2.selectedProperty().addListener(mineChangeListener);
item2Level1.getChildren().add(item4Level2);
Mine mine7 = new Mine("subtest3", true);
CheckBoxTreeItem<Mine> item5Level2 = new CheckBoxTreeItem<>(mine7, null, mine6.isEnabled());
item5Level2.setExpanded(true);
//item5Level2.setIndependent(true);
item5Level2.selectedProperty().addListener(mineChangeListener);
item4Level2.getChildren().add(item5Level2);
contentPane.getChildren().add(treeView);
primaryStage.setScene(new Scene(contentPane));
primaryStage.setWidth(200);
primaryStage.setHeight(400);
primaryStage.setTitle("JavaFX 8 app");
primaryStage.setOnCloseRequest(event -> Platform.exit());
primaryStage.show();
}
private class MineChangeListener implements ChangeListener<Boolean> {
/* (non-Javadoc)
* @see javafx.beans.value.ChangeListener#changed(javafx.beans.value.ObservableValue, java.lang.Object, java.lang.Object)
*/
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
CheckBoxTreeItem<Mine> item = (CheckBoxTreeItem<Mine>) treeView.getSelectionModel().getSelectedItem();
if (newValue) {
// Do some work on the data in the selected TreeItem
}
}
}
}
package com.company;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.CheckBoxTreeCell;
import javafx.util.Callback;
public class MineTreeCellFactory implements Callback<TreeView<Mine>, TreeCell<Mine>> {
/* (non-Javadoc)
* @see javafx.util.Callback#call(java.lang.Object)
*/
@Override
public TreeCell<Mine> call(TreeView<Mine> param) {
CheckBoxTreeCell<Mine> cell = new CheckBoxTreeCell<Mine>() {
/* (non-Javadoc)
* @see javafx.scene.control.Cell#updateItem(java.lang.Object, boolean)
*/
@Override
public void updateItem(Mine item, boolean empty) {
if (item == getItem() || (item != null && item.equals(getItem()))) {
return;
}
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (item != null) {
setText(item.getName());
} else {
setText(null);
setGraphic(null);
}
}
}
};
return cell;
}
}
package com.company;
import javafx.beans.property.SimpleBooleanProperty;
public class Mine {
private final String name;
private final SimpleBooleanProperty enabled;
public Mine(String name, boolean enabled) {
this.name = name;
this.enabled = new SimpleBooleanProperty(enabled);
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the description
*/
public String getDescription() {
return description;
}
public SimpleBooleanProperty enabledProperty() {
return enabled;
}
/**
* @return the isDisabled
*/
public boolean isEnabled() {
return enabled.get();
}
}