JavaFX - strange behavior of TreeView when deleting a selected item

In my application, I have TreeViewon the left side, and I am updating the panel on the right side according to the selection in TreeView. Very direct scenario. When the choice is zero, I display a message, for example, "make a choice" in the panel, i.e. I also handle null selections inTreeView .

During the life of the application, some elements can be added / removed from TreeView. I am having problems when the selected item is TreeViewdeleted. In this case, I expected the choice to TreeViewbecome zero, however it is not!

To debug this case, I filed an expression with simple FXML, as shown below:

FXMLDocument.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="350.0" prefWidth="250.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="treeviewbug.FXMLDocumentController">
  <children>
    <TreeView fx:id="treeView" prefHeight="350.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="50.0" />
    <Button mnemonicParsing="false" onAction="#update" text="update" AnchorPane.leftAnchor="20.0" AnchorPane.topAnchor="15.0" />
    <Label fx:id="selectionLabel" text="" AnchorPane.leftAnchor="100.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="20.0" />
  </children>
</AnchorPane>

FXMLDocumentController.java:

package treeviewbug;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.util.Callback;

public class FXMLDocumentController implements Initializable {

    @FXML
    Label selectionLabel;
    @FXML
    private TreeView<String> treeView;
    private TreeItem<String> selectedItem = null;
    private ChangeListener<String> changeListener = new ChangeListener<String>() {

        @Override
        public void changed(ObservableValue<? extends String> ov, String oldValue, String newValue) {
            selectionLabel.setText(newValue);
        }
    };

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        final TreeItem<String> root = new TreeItem<>();
        for (int i = 1; i <= 20; i++) {
            root.getChildren().add(new TreeItem<String>("Item " + i));
        }
        treeView.setShowRoot(false);
        treeView.setRoot(root);
        treeView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TreeItem<String>>() {

            @Override
            public synchronized void changed(ObservableValue<? extends TreeItem<String>> ov, TreeItem<String> oldSelection, TreeItem<String> newSelection) {
                if (selectedItem != null) {
                    selectedItem.valueProperty().removeListener(changeListener);
                }
                if (newSelection == null) {
                    selectionLabel.setText("selection is null");
                } else {
                    selectionLabel.setText(newSelection.getValue());
                }
                selectedItem = newSelection;
                if (selectedItem != null) {
                    selectedItem.valueProperty().addListener(changeListener);
                }
            }
        });
        treeView.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {

            @Override
            public TreeCell<String> call(TreeView<String> p) {
                System.out.println("Creating new cell.");
                return new TreeCell<String>() {

                    Label label = new Label();
                    Button button = new Button("remove");
                    HBox box = new HBox(20);
                    {
                        button.setOnAction(new EventHandler<ActionEvent>() {

                                @Override
                                public void handle(ActionEvent t) {
                                    TreeItem<String> itemToRemove = null;
                                    for (TreeItem<String> item : root.getChildren()) {
                                        if (item.getValue().equals(getItem())) {
                                            itemToRemove = item;
                                            break;
                                        }
                                    }
                                    if (itemToRemove != null) {
                                        root.getChildren().remove(itemToRemove);
                                    }
                                    t.consume();
                                }
                            });
                        box.getChildren().addAll(label, button);
                    }

                    @Override
                    protected void updateItem(String value, boolean bln) {
                        super.updateItem(value, bln);
                        if (value != null) {
                            label.setText(value);
                            setGraphic(box);
                        } else {
                            setGraphic(null);
                        }
                    }
                };
            }
        });
    }

    @FXML
    private void update() {
        TreeItem<String> i = treeView.getSelectionModel().getSelectedItem();
        if (i == null) {
            selectionLabel.setText("selection is null");
        } else {
            selectionLabel.setText(i.getValue());
        }
    }

}

TreeView 20 . selectedItemProperty, TreeItem. valueProperty TreeItem, - , - . , . , , , , - .

, , . , TreeView!

: ? - - ?

for:

root.getChildren().addListener(new ListChangeListener<TreeItem<String>>() {

            @Override
            public void onChanged(ListChangeListener.Change<? extends TreeItem<String>> change) {
                while (change.next()) {
                    if (change.wasRemoved() && selectedItem != null) {
                        if (change.getRemoved().contains(selectedItem)) {
                            selectedItem.valueProperty().removeListener(changeListener);
                            selectedItem = null;
                            treeView.getSelectionModel().clearSelection();
                        }
                    }
                }
            }
        });

, . , clearSelection(). , ?

, ?

, . , :)

+3
2

Java 1.8.0_92 :

  • , , . selectIndex ,
  • . , selectedIndex ( selectedItem ),
  • , Index . ; . SelectedIndex .

, . selectedIndex selectedItem , Gman. (, ).

root-children .

onAction :

button.setOnAction(t -> {
    TreeItem<String> item = getTreeItem();
    item.getParent().getChildren().remove(item);        // remove item
    if(treeView.getRoot().getChildren().size() == 0) {  // check for empty tree
        treeView.getSelectionModel().clearSelection();
    }
    t.consume();
});
+1

, root node.

    final TreeItem<String> root = new TreeItem<>();
    for (int i = 1; i <= 20; i++) {
        root.getChildren().add(new TreeItem<String>("Item " + i));
    }
    treeView.setShowRoot(false);
    treeView.setRoot(root);

:

private ObservableList<TreeItem<String>> obsTreeItems;
private List<TreeItem<String>> treeItems;

:

    treeItems = new ArrayList<>();
    final TreeItem<String> root = new TreeItem<>();
    for (int i = 1; i <= 20; i++) {
        /*root.getChildren().add(new TreeItem<String>("Item " + i));*/
        treeItems.add(new TreeItem<String>("Item "+i));
    }
    //observable collection
    obsTreeItems = FXCollections.observableArrayList(treeItems);

    //add items as observable list to root
    root.getChildren().addAll(obsTreeItems);

    treeView.setShowRoot(false);
    treeView.setRoot(root);

, . . .

-1

All Articles