Search code examples
javafxjavafx-8selectedindextreetableviewselecteditemchanged

Removing a JavaFX TreeItem Sometimes Changes TreeTableView Selection


I have a JavaFX TreeTableView. Under its root, there is a set of TreeItem (nodes) and each node may have its own child TreeItem (sub-nodes). Since there is no information to show for any nodes without sub-nodes, I want to remove those. But somehow, the simple remove action sometime changes the selection.

package sample;

import javafx.application.Application;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        TreeItem<String> rootNode = new TreeItem<String>("Root");
        rootNode.setExpanded(true);
        rootNode.getChildren().setAll(new TreeItem<>("Node 0"),
                new TreeItem<>("Node 1"), new TreeItem<>("Node 2"),//);
                new TreeItem<>("Node 3"), new TreeItem<>("Node 4"));
        for (int i = 0; i < 2; i++) {
            TreeItem<String> node = rootNode.getChildren().get(i);
            node.setExpanded(true);
            node.getChildren().setAll(new TreeItem<>("Sub Node " + i + "-0"),
                    new TreeItem<>("Sub Node " + i + "-1"),
                    new TreeItem<>("Sub Node " + i + "-2"));
        }

        TreeTableColumn<String, String> column = new TreeTableColumn<>("Nodes");
        column.setCellValueFactory((TreeTableColumn.CellDataFeatures<String, String> p) -> {
            return new ReadOnlyStringWrapper(p.getValue().getValue());
        });
        column.setPrefWidth(200);

        TreeTableView<String> table = new TreeTableView<>(rootNode);
        table.getColumns().add(column);

        int selectIndex = 4;
        int removeIndex = 3;
        table.getSelectionModel().select(selectIndex);
        System.out.println("Selected index = " + table.getSelectionModel().getSelectedIndex());
        System.out.println("Selected item  = " + table.getSelectionModel().getSelectedItem().getValue());
        table.getRoot().getChildren().remove(removeIndex);
        System.out.println("Selected index = " + table.getSelectionModel().getSelectedIndex());
        System.out.println("Selected item  = " + table.getSelectionModel().getSelectedItem().getValue());

        primaryStage.setTitle("Tree Table View Selection");
        primaryStage.setScene(new Scene(table, 300, 275));
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

The code as it is produces the following output:

Selected index = 4
Selected item  = Sub Node 0-2
Selected index = 3
Selected item  = Sub Node 0-1

However, if (selectedIndex, removeIndex) is changed to (3,4), then the output becomes:

Selected index = 3
Selected item  = Sub Node 0-1
Selected index = 3
Selected item  = Sub Node 0-1

No change in selected index.

In fact, in my limited testing case, as long as selectedIndex is less or equal to removeIndex, then the remove action does not change the selection. Otherwise it changes the selection.

Why does it happen this way? Is there a way to get around this problem?


Solution

  • It appears it is a bug in java. I reported it to bugs.java.com and it is now listed as JDK-8193442 and currently no fix yet.

    A work around is to save the selectedItem before remove TreeItem, and call select after the removal. One need to watch out any changelistener on the selectedItemProperty, though.