Oliver
Oliver

Reputation: 11597

Swing JTree icon rendering

I want to have a JTree in my swing application that does not have an icon for leaf nodes, so I wrote the following code:

    DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer)
        jtree.getCellRenderer();
    renderer.setLeafIcon(null);
    jtree.setCellRenderer(renderer);

This correctly removes the icons for leaves, but it also results in the following rendering error:

Badly rendered tree

You can see that the labels attached to the branch nodes are truncated, and they are bunched too close together. If I expand and then collapse all the branch nodes, the problem fixes itself:

enter image description here

If I comment out the line:

renderer.setLeafIcon(null);

The problem goes away (but the leaf icon, which I don't want, is present.)

Any ideas how to fix this?

Edit: I'll add all the relevant code.

public class StepChooserPanel extends JScrollPane { 
private JTree rules;

public StepChooserPanel(TabPanel parent){
    super();

    this.setBackground(Color.white);


    DefaultMutableTreeNode top = new DefaultMutableTreeNode("top");
    rules = new JTree();
    rules.getSelectionModel()
        .setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
    rules.setRootVisible(false);
    rules.setScrollsOnExpand(false);
    rules.setToggleClickCount(1);
    rules.addTreeSelectionListener(parent);
    rules.putClientProperty("JTree.lineStyle", "None");


    DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer)
        rules.getCellRenderer();
    renderer.setLeafIcon(null);
    rules.setCellRenderer(renderer);

    this.setViewportView(rules);

}

public void populateFilterRules(InferenceSystem system){

    DefaultMutableTreeNode root = new DefaultMutableTreeNode();
    TreeModel treeModel = new DefaultTreeModel(root);
    rules.setModel(treeModel);

    List<Rule> systemRules = system.getSortedRules();       
    for(int i = 0; i < systemRules.size(); i++){
        if(!(systemRules.get(i) instanceof InferenceRule)){
            continue;
        }
        DefaultMutableTreeNode rule = new DefaultMutableTreeNode
                (systemRules.get(i).getName());
        root.add(rule);
    }

    rules.expandPath(new TreePath(root.getPath())); 

    this.repaint();     
}

public void populateRewriteList(Collection<Rewrite> choices){

    DefaultMutableTreeNode root = (DefaultMutableTreeNode) rules.getModel()
        .getRoot();

    for(Rewrite rr : choices){
        for (int i = 0; i < root.getChildCount(); i++){
            String ruleName = (String) ((DefaultMutableTreeNode)root.getChildAt(i))
                                    .getUserObject();
            if(rr.getRule().getName().equals(ruleName)){
                ((DefaultMutableTreeNode)root.getChildAt(i))
                    .add(new DefaultMutableTreeNode(rr));
            }
        }           
    }   

    this.repaint();
}

All the setup is done in the constructor. populateFilterRules is called, which adds in the branch nodes. Then populateRewriteList is called, which adds in the leaf nodes to the right places. repaint is called after these changes are made. The containing JScrollPane class is wrapped into a JSplitPane, which is rendered into the frame.

Upvotes: 2

Views: 2089

Answers (2)

trashgod
trashgod

Reputation: 205785

An alternative is to use an implementation having no pixels, as suggested here.

Upvotes: 1

jzd
jzd

Reputation: 23629

This works fine for me. Double check that there is not something else going on.

If you are changing this after the tree has been displayed, make sure you are repainting the tree.

An ugly work around might be a 100% transparent icon instead of null.

Upvotes: 1

Related Questions