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

Provide a setItems method for TreeView

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • fx2.1
    • javafx
    • None

      I miss a setItems method for the TreeView control as it exists in ListView.

      I favor separation of view and logic and as it is now, you have to mix view and logic together. It is not easy to sort the tree items, or to add or to remove single items in the tree.
      In contrary e.g. the ListView does all the UI logic quite well, if you sort the underlying ObservableList or remove/add items.

      It would be nice to have this method in TreeView integrated.

      I borrowed some ideas from Flex ( http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/collections/HierarchicalData.html ) and implemented this behavior for my TreeView(s). The hierarchical (recursive) nature of the tree is represented by a ObservableList<HierarchicalTreeItem>, where HierarchicalTreeItem is a item which holds a children list of HierarchicalTreeItems:

      public interface HierarchicalTreeItem<T extends HierarchicalTreeItem> {
          ObservableList<T> getChildren();
      }


      The setItems method of my TreeView then expects a list of HierarchicalTreeItem as data source.

      Here is my implementation. I don't know if it is perfect, or if I am missing some things, but it works for me.

      *EDIT* (old implementation had some issues, if you have an object in several trees or treeitems)

      import javafx.collections.ListChangeListener;
      import javafx.collections.ObservableList;
      import javafx.scene.control.TreeItem;
      import javafx.scene.control.TreeView;

      import java.util.HashMap;
      import java.util.Map;

      /**
       * @author Christian Schudt
       */
      public class TreeViewWithItems<T extends HierarchyData<T>> extends TreeView<T> {

          public TreeViewWithItems(TreeItem<T> root) {
              super(root);
          }

          /**
           * Sets items for the tree.
           *
           * @param list The list.
           */
          public void setItems(ObservableList<? extends T> list) {

              for (T value : list) {
                  getRoot().getChildren().add(addRecursively(value));
              }

              list.addListener(getListChangeListener(getRoot()));
          }


          private Map<TreeItem<T>, ListChangeListener<T>> map = new HashMap<TreeItem<T>, ListChangeListener<T>>();

          /**
           * Gets a {@link javafx.collections.ListChangeListener} for a {@link TreeItem}. It listens to changes on the underlying list and updates the UI accordingly.
           *
           * @param treeItem The tree item which holds the list.
           * @return The listener.
           */
          private ListChangeListener<T> getListChangeListener(final TreeItem<T> treeItem) {
              return new ListChangeListener<T>() {
                  @Override
                  public void onChanged(final Change<? extends T> change) {
                      while (change.next()) {
                          if (change.wasRemoved()) {
                              for (T removed : change.getRemoved()) {

                                  for (TreeItem<T> item : treeItem.getChildren()) {
                                      if (item.getValue().equals(removed)) {
                                          treeItem.getChildren().remove(item);
                                          removeRecursively(item);
                                          break;
                                      }
                                  }

                              }
                          }
                          // If items have been added
                          if (change.wasAdded()) {
                              ObservableList<? extends T> list = change.getList();

                              // Get the new items
                              for (int i = change.getFrom(); i < change.getTo(); i++) {
                                  treeItem.getChildren().add(i, addRecursively(list.get(i)));
                              }
                          }
                          // If the list was sorted.
                          if (change.wasPermutated()) {
                              // Store the new order.
                              Map<Integer, TreeItem<T>> tempMap = new HashMap<Integer, TreeItem<T>>();

                              for (int i = change.getFrom(); i < change.getTo(); i++) {
                                  int a = change.getPermutation(i);
                                  tempMap.put(a, treeItem.getChildren().get(i));
                              }
                              getSelectionModel().clearSelection();
                              treeItem.getChildren().clear();

                              // Add the items in the new order.
                              for (int i = change.getFrom(); i < change.getTo(); i++) {
                                  treeItem.getChildren().add(tempMap.get(i));
                              }
                          }
                      }
                  }
              };
          }

          /**
           * Removes the listener recursively.
           *
           * @param item The tree item.
           */
          private void removeRecursively(TreeItem<T> item) {
              if (item.getValue() != null && item.getValue().getChildren() != null) {
                  item.getValue().getChildren().removeListener(map.remove(item));

                  for (TreeItem<T> treeItem : item.getChildren()) {
                      removeRecursively(treeItem);
                  }
              }
          }


          /**
           * Adds the children to the tree recursively.
           *
           * @param value The initial value.
           * @return The tree item.
           */
          private TreeItem<T> addRecursively(T value) {

              TreeItem<T> treeItem = new TreeItem<T>();
              treeItem.setValue(value);
              treeItem.setExpanded(true);

              if (value != null && value.getChildren() != null) {
                  ListChangeListener<T> listChangeListener = getListChangeListener(treeItem);
                  value.getChildren().addListener(listChangeListener);

                  map.put(treeItem, listChangeListener);
                  for (T child : value.getChildren()) {
                      treeItem.getChildren().add(addRecursively(child));
                  }
              }
              return treeItem;
          }
      }

            Unassigned Unassigned
            cschudtjfx Christian Schudt (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Imported: