Module MaterialFX

Class MFXTreeItemSkin<T>

java.lang.Object
javafx.scene.control.SkinBase<MFXTreeItem<T>>
io.github.palexdev.materialfx.skins.MFXTreeItemSkin<T>
All Implemented Interfaces:
Skin<MFXTreeItem<T>>
Direct Known Subclasses:
MFXCheckTreeItemSkin

public class MFXTreeItemSkin<T> extends SkinBase<MFXTreeItem<T>>
This is the implementation of the Skin associated with every MFXTreeItem.

Extends SkinBase.

This class is important because it's what defines the layout of any MFXTreeItem, from the cell to the container to the expand/collapse animations.

The base container is a VBox. It contains the item's cell and (N.B!!) other items so if you look at the children you will see something like this:
     
     SimpleTreeCell@b91283f
     MFXTreeItem@77adfda
     MFXTreeItem@58b4c4ce
     MFXTreeItem@49d9b6c6
     
 
The container has its max and min heights set to use PREF_SIZE. The prefHeight is adjusted programmatically when an EXPAND/COLLAPSE event occurs or when a ADD/REMOVE event occurs and the item is expanded.

To create the expand/collapse effect the container is clipped with a Rectangle which height and width are bound to the container ones.

Since the view (this skin) is separated from the control (the MFXTreeItem) and the items list is part of the latter we add a listener to the list here so that when one or more items are added to the list and this item is expanded or set to start expanded then we can add/remove the items from the container and adjust its height accordingly by firing an ADD_REMOVE_ITEM_EVENT.

This separation though has a problem. If you add an item to a precise index the listener doesn't carry the index so the only way to keep the desired order is to sort the container children list accordingly to the items list:

     FXCollections.sort(box.getChildren(), Comparator.comparingInt(item.getItems()::indexOf));
 
Also in the constructor we check if the AbstractMFXTreeItem.startExpandedProperty() is set to true. In that case for avoiding issues with events and layout we set a special flag forcedUpdate to true, the whe add all the items to the container, apply css, ask to layout so the height updates, then we set its prefHeight, update the cell, set the item expand state to true (that's why the expand property is for internal use only) and after all that we reset the forcedUpdate flag to false.
  • Constructor Details

    • MFXTreeItemSkin

      public MFXTreeItemSkin(MFXTreeItem<T> item)
  • Method Details

    • updateDisplay

      protected void updateDisplay()
      This method is called when the item is about to expand/collapse.

      If the item needs to be expanded then we add all the items to the container, apply css, ask to layout so the height updates, the we fire an EXPAND_EVENT on the item to handle the resize and the animation.

      If the item needs to be collapsed then we fire a COLLAPSE_EVENT on the item to handle the resize and animation. Note that the items are not yet removed but they are removed at the end of the animation.

    • buildAnimation

      protected void buildAnimation(double fHeight)
      Build the expand/collapse animation setting the container prefHeight property to the fHeight parameter. Also build the rotate animation for the cell's disclosure node.

      Last but not least so N.B! the item's MFXTreeItem.animationRunningProperty() is bound to this animation status property and used in animationIsRunning() method.

      Parameters:
      fHeight - the final height of the container. The value is usually calculated by computeExpandCollapse()
    • animationIsRunning

      protected boolean animationIsRunning()
      Check if the animation is running on the item or its parent up to the root. This is used in createCell() when adding the event handler to the cell's disclosure node.
    • computeExpandCollapse

      protected double computeExpandCollapse()
      This method is responsible for calculating the final height the item should have after an expand/collapse event. It's also used in the constructor in case the start expanded property is set to true.
      Returns:
      the computed height as the sum of all items height
    • createCell

      protected AbstractMFXTreeCell<T> createCell()
      This method is responsible for calling the MFXTreeItem's AbstractMFXTreeItem.cellFactoryProperty() thus creating the cell and adding an event handler for MOUSE_PRESSED on its disclosure node. If the items list is empty we consume the event and return. If the animationIsRunning() method returns true we return too and the MFXTreeItem.expandedProperty() is not updated. So we avoid playing multiple animations at the same time because it could mess up the layout, also that's why it's recommended to not use too high values for MFXTreeItem.animationDurationProperty().

      At the end if all is ok, we update the MFXTreeItem.expandedProperty() thus calling updateDisplay and firing the proper events.

      We also update the cell.
      Returns:
      the created cell
      See Also:
    • dispose

      public void dispose()
      Specified by:
      dispose in interface Skin<T>
      Overrides:
      dispose in class SkinBase<MFXTreeItem<T>>