Uzi's Blogs

Things I learn, observe and try out

Monday, August 28, 2006

Setting Custom icon for individual nodes in JTree

For changing and removing the Default Icons in a JTree Component see following link:
http://javaalmanac.com/egs/javax.swing.tree/DefIcons.html

However, above approach does not take care of individual icons. Here is the solution that I used in one of my projects:

1. Let your nodes extend from a generic super class, say MyNode, where MyNode is extended from DefaultMutableTreeNode. Define public abstract Icon getIcon(); in MyNode.


/**
* My Node
* @author usman
*/
public abstract class MyNode extends DefaultMutableTreeNode{

 public MyNode () {
  super("Title Of Node);
 }

 public abstract javax.swing.Icon getIcon();
}


2. Create sub classes of MyNode which are supposed to be inserted into the tree, implementing getIcon method, for instance:

/**
* Custom Node
* @author usman
*/
public class CustomNode extends MyNode{

 public CustomNode() {
  super("Title Of Node);
 }

 public
javax.swing.Icon getIcon() {
  return new javax.swing.ImageIcon(getClass().getResource("/icons/myicon16.png"));
 }
}

Now create a custom tree cell renderer, in which you set the default icon based on the sub class type:

import java.awt.Component;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;

public class CustomTreeCellRenderer extends DefaultTreeCellRenderer{
 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
 if((value instanceof MyNode) && (value != null)) {
  setIcon(((MyNode)value).getIcon());
  }

//we can not call super.getTreeCellRendererComponent method, since it overrides our setIcon call and cause rendering of labels to '...' when node expansion is done

//so, we copy (and modify logic little bit) from super class method:

 String stringValue = tree.convertValueToText(value, sel,
expanded, leaf, row, hasFocus);

 this.hasFocus = hasFocus;
 setText(stringValue);
 if(sel)
   setForeground(getTextSelectionColor());
 else
   setForeground(getTextNonSelectionColor());

 if (!tree.isEnabled()) {
   setEnabled(false);
 }
 else {
   setEnabled(true);
 }
  setComponentOrientation(tree.getComponentOrientation());
 selected = sel;
 return this;

}
}


The method of interest is getTreeCellRendererComponent in which we call getIcon method of our sub classes and sets the icon of current node. We don't call super class method directly because it somehow mess up with default width calculation of our nodes and cause '...' in rendering the labels. The '...' is specially visible if we programmatically expand children of a node.

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home