Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8088194

TreeView keyboard focus moves to unexpected node when child nodes are added

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P4
    • 9
    • 8u20, 8u25
    • javafx
    • Windows 7

    Description

      I am dynamically adding child nodes to a TreeView - a typical example would be using the TreeView to display a folder hierarchy with a filesystem watcher that updates the TreeView in response to changes made to the filesystem.

      I find that if the currently selected node is below a node where I'm adding children, then after the add the keyboard focus is set to a different tree item than what is currently selected. Run the code below, it will programatically expand the tree and then select the last node. After 5 seconds 3 new nodes will be added in the middle. The selected node will remain the last node in the tree (as expected), but keyboard focus will shift a couple of nodes higher up (click inside the app window to ensure keyboard focus is visible). I would expect keyboard focus in this case to follow the selected item.

      I think the issue is around line 1535 of TreeView.java - of the 3 items added, only the first one passes the if clause, so shift is only incremented by one. It could be because getFocusedIndex() is effectively constant during this loop and doesn't take into account the shift in focus that is being calculated?

      ====== Demo code below =======

      import javafx.animation.KeyFrame;
      import javafx.animation.Timeline;
      import javafx.application.Application;
      import javafx.scene.Scene;
      import javafx.scene.control.SelectionMode;
      import javafx.scene.control.SelectionModel;
      import javafx.scene.control.TreeItem;
      import javafx.scene.control.TreeView;
      import javafx.stage.Stage;
      import javafx.util.Duration;

      public class TreeViewFocusIssueDemo extends Application{

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

          @Override
          public void start(Stage primaryStage) throws Exception {
              TreeItem<String> root = new TreeItem<>("Root");
              root.getChildren().addAll(expandableTreeItem("One"), expandableTreeItem("Two"), expandableTreeItem("Three"));
              TreeView treeView = new TreeView(root);
              treeView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);

              Timeline timer = new Timeline(new KeyFrame(Duration.seconds(5), event ->
                      root.getChildren().get(1).getChildren().addAll(expandableTreeItem("A"), expandableTreeItem("B"), expandableTreeItem("C")
              )));

              Scene scene = new Scene(treeView);
              primaryStage.setScene(scene);
              primaryStage.show();

              // expand all and select last item (same behaviour whether this is done programatically or by the user)
              root.setExpanded(true);
              root.getChildren().forEach(c -> c.setExpanded(true));
              treeView.getSelectionModel().select(root.getChildren().get(2));

              timer.play();
          }

          private static <V> ExpandableTreeItem<V> expandableTreeItem(V value) {
              return new ExpandableTreeItem<>(value);
          }

          public static class ExpandableTreeItem<T> extends TreeItem<T>{
              private boolean isLeaf = false;

              public ExpandableTreeItem(T value) {
                  super(value);
              }

              @Override
              public boolean isLeaf() {
                  return isLeaf;
              }
          }
      }

      Attachments

        Issue Links

          Activity

            People

              jgiles Jonathan Giles
              duke J. Duke
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:
                Imported: