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

CheckBoxTreeCell: graphic on TreeItem not always showing

XMLWordPrintable

    • b14

      To reproduce, compile and run the example below

      - expand and collapse root by clicking into the expansion icon
      - expected: graphic of root must be visible always
      - actual: graphic not showing

      Note that the actual # of expand/collapse or which children to expand/collapse and which graphics are effected is a bit unpredictable (read: could not find a pattern).

      A bit of digging revealed that the treeItem's graphic is set as the graphic of the checkBox and appears to not be removed properly. So on re-use of the cell, the checkBox still contains the old graphic which leads to removing it from its real target.

      While I don't know where exactly the cleanup of the box' graphic should happen, a quick hack seems to be to null the box' graphic in updateItem, see WCheckBoxTreeCell in the example below.

      public class CheckBoxTreeCellWithGraphic extends Application {

          @SuppressWarnings("unchecked")
          private Parent createContent() {
              
              TreeItem<String> root = new TreeItem<>("ROOT", new Label("really"));
              root.getChildren().add(new TreeItem<>("firstChild"));
              root.getChildren().add(new TreeItem<>("secondChild"));
              
              root.getChildren().forEach(child -> {
                  child.getChildren().addAll(
                          new TreeItem<>(" of " + child.getValue(), new Label("grand1 "))
                          ,new TreeItem<>(" of " + child.getValue(), new Label("grand2"))
                          );
                  child.setGraphic(new Button(child.getValue()));
              });
              
              TreeView<String> tree = new TreeView<>(root);
              // core checkBoxTreeCell
              tree.setCellFactory(CheckBoxTreeCell.forTreeView());
              // hacked checkBoxTreeCell
      // tree.setCellFactory(c -> new WCheckBoxTreeCell<>());
              
              return new BorderPane(tree);
          }

          public static class WCheckBoxTreeCell<T> extends CheckBoxTreeCell<T> {
              
              CheckBox checkBoxAlias;
              public WCheckBoxTreeCell() {
                  InvalidationListener checkBoxGrabber = new InvalidationListener() {
                      
                      @Override
                      public void invalidated(Observable observable) {
                          if (checkBoxAlias == null) {
                              if (getGraphic() instanceof CheckBox) {
                                  checkBoxAlias = (CheckBox) getGraphic();
                                  graphicProperty().removeListener(this);
                              }
                          }
                      }
                      
                  };
                  graphicProperty().addListener(checkBoxGrabber);
              }
              
              @Override
              public void updateItem(T item, boolean empty) {
                  if (checkBoxAlias != null) {
                      checkBoxAlias.setGraphic(null);
                  }
                  super.updateItem(item, empty);
             }
       
          }

          @Override
          public void start(Stage stage) throws Exception {
              stage.setScene(new Scene(createContent()));
              stage.setTitle(FXUtils.version());
              stage.show();
          }

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

          @SuppressWarnings("unused")
          private static final Logger LOG = Logger
                  .getLogger(CheckBoxTreeCellWithGraphic.class.getName());
      }

            nlisker Nir Lisker
            fastegal Jeanette Winzenburg
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: