views:

361

answers:

1

Using the new version of the substance look and feel for Java, the connecting lines in a typical JTree are not drawn (parent - child lines).

In the official forum in java.net someone asked the same thing and the answer of the developer for this is that it was a choice based on the newer UI's and there is no plan to implement the option in the future.

His answer also said that you could implement this yourself by subclassing the SubstanceUI class and implementing the paintHorizontalPartOfLeg / paintVerticalPartOfLeg methods.

Can someone either explain the process needed or maybe give me an example? I'm sure that someone must have done this since it is a very weird choice on behalf of the developer not to draw these lines.

+3  A: 

This is all going from memory. I will edit if I find anything wrong with this tomorrow.

check out BasicTreeUI or MetalTreeUI. I believe they both paint lines.

What you need to do is create a new class that extends (I'm guessing on the name here) SubstanceTreeUI and override paintHorizontalPartOfLeg() and paintVerticalPartOfLeg(). Then you have a choice:

  1. You can call myTree.setUI( new MyTreeUI() )
  2. UIManager.getDefaults().put("TreeUI", MyTreeUI.class.getName() ) at some point before you make your JTree

If you don't want to subclass, try UIManager.getDefaults().put("TreeUI", BasicTreeUI.class.getName() ) and see if that looks ok.

EDIT 2: After further review it would be easier to just call .setUI(new BasicTreeUI()) on your JTree or call UIManager.getDefaults().put("TreeUI", BasicTreeUI.class.getName() ) before creating your tree.

EDIT:
SubstanceTreeUI is a cubclass of BasicTreeUI. It has overridden paintXXXPartOfLeg().

Horiz:

@Override
protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
     Insets insets, Rectangle bounds, TreePath path, int row,
     boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf) {
    boolean toPaint = (!this.tree.isEnabled())
      || this.isInside
      || !FadeConfigurationManager.getInstance().fadeAllowed(
        SubstanceLookAndFeel.TREE_DECORATIONS_ANIMATION_KIND,
        tree);
    if (FadeTracker.getInstance().isTracked(this.tree, SubstanceLookAndFeel.TREE_DECORATIONS_ANIMATION_KIND)) {
     Graphics2D graphics = (Graphics2D) g.create();
     graphics.setComposite(TransitionLayout
       .getAlphaComposite(this.tree,
         FadeTracker.getInstance()
          .getFade10(this.tree,SubstanceLookAndFeel.TREE_DECORATIONS_ANIMATION_KIND) / 10.0f,
          g));
     super.paintHorizontalPartOfLeg(graphics, clipBounds, insets,
       bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
     graphics.dispose();
    } else if (toPaint) {
     super.paintHorizontalPartOfLeg(g, clipBounds, insets, bounds, path,
       row, isExpanded, hasBeenExpanded, isLeaf);
    }
}

It looks like the lines are only painted if either of the following is true:

  • The Tree is not enabled, the mouse is in the tree bounds [this.inside] and fading (?) is not allowed on the tree [!FadeConfigurationManager.getInstance().fadeAllowed(...)]
  • The FadeTracker is tracking the JTree [FadeTracker.getInstance().isTracked(...)]

Figure out how to ensure that the JTree is being Tracked by the FadeTracker or try this VERY rough hack (see below):

You could also cut and paste the code from BasicTreeUI's paintXXXPartOfLeg methods into a subclass.

public MyTree extends JTree {
    private boolean overrideIsEnable = false;
    public void setOverrideIsEnable(boolean b) { overrideIsEnabeld=true; }
    public boolean isOverrideIsEnable(boolean b) { return overrideIsEnabeld; }
    public boolean isEnabled() {
     if(overrideIsEnabled) return false;
     return super.isEnabled();
    }
}


class MyTreeUI extends SubstanceTreeUI {
protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
        Insets insets, Rectangle bounds, TreePath path, int row,
        boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf) {
if(this.tree instanceof MyTree)
try {
   Field f = SubstanceTreeUI.class.getDeclaredField("inside");
   f.setAccessible(true);
   Boolean v = (Boolean)f.get(this);
   f.set(this,Boolean.true);
   ((MyTree)this.tree).setOverrideIsEnable(true);
} catch(Throwable t) {
   //want to default back to substanceUI if this fails.
}
super.paintHoriz.....();
try{
    f.set(this,v);
    ((MyTree)this.tree).setOverrideIsEnable(true);
}catch(Throwable t) {
   //see above
}
}
//repeat for Vertical
}
KitsuneYMG
Thank you for your answer. What i am actually interested in, is how exactly do i draw the lines once i subclass and implement the methods. (Mind you the substanceUI class does not have these methods. it's not a descendant of BasicUI). Could you maybe give me a small example or point me to a direction where i can find info?
Savvas Dalkitsis
Please take a look at my edited answer. FYI You do not want to be looking at SubstanceUI, you want to be looking at SubstanceTreeUI, which (according to google) has both methods.
KitsuneYMG
thank you very much. Your answer is right on the spot. very helpful.
Savvas Dalkitsis
Which one? I outline several. I'm just interested in which you tried and which you liked best.
KitsuneYMG
For anyone else who's googled across this answer:UIManager.getDefaults().put("TreeUI", BasicTreeUI.class.getName() );Worked perfectly for me (remember to put it before the creation of your JTree) using Substance. This is, however, with custom Icons for each of my JTree nodes (I'm not sure how it will look otherwise).Thankyou!
Andrew