4

I want to display separate icon for grouped and ungrouped nodes.I created a customTreeCellRender.My sample codes given below.In for loop odd one nodes have one icon and evens have another.But not change the icon of nodes.In my application ,populating tree nodes from db and grouping based on some conditions.This is a sample runnable code.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;

public class TestTree extends JDialog {

    JTree tree;

    DefaultTreeModel treeModel;

    public TestTree() {
        setSize(300, 800);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        System.out.println(getContentPane().getBackground());
    }

    protected static ImageIcon createImageIcon(String path) throws MalformedURLException {
        java.net.URL imgURL = new URL(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }

    public void init() throws MalformedURLException {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Numbers");
        treeModel = new DefaultTreeModel(root);
        tree = new JTree(treeModel);
        tree.setBackground(new Color(238, 238, 244));
        tree.setOpaque(true);

        CustomIconRenderer customIconRenderer = new CustomIconRenderer(true);
        customIconRenderer.setTextSelectionColor(Color.white);
        customIconRenderer.setBackgroundSelectionColor(Color.blue);
        customIconRenderer.setBorderSelectionColor(Color.black);
        customIconRenderer.setBackgroundNonSelectionColor(new Color(238, 238,
                244));
        ImageIcon icon = createImageIcon("https://i.stack.imgur.com/wCF8S.png");
        customIconRenderer.setLeafIcon(icon);


        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0) {
                DefaultMutableTreeNode subroot = new DefaultMutableTreeNode(
                        "node_" + i);
                root.add(subroot);

                    tree.setCellRenderer(new CustomIconRenderer(false));

                if (i % 3 == 0) {
                    for (int j = 10; j < 15; j++) {
                        DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(
                                "node_" + j);
                        subroot.add(leaf);
                    }
                }

            } else {
                DefaultMutableTreeNode subroot = new DefaultMutableTreeNode(
                        "node_" + i);
                root.add(subroot);
                tree.setCellRenderer(new CustomIconRenderer(true));
                if (i % 4 == 0) {
                    for (int j = 15; j < 20; j++) {
                        DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(
                                "node_" + j);
                        subroot.add(leaf);
                    }

                }

            }
        }

        for (int i = 0; i < tree.getRowCount(); i++) {
            tree.expandRow(i);
        }

        tree.setCellRenderer(customIconRenderer);

        getContentPane().add(tree, BorderLayout.CENTER);
    }

    public static void main(String args[]) throws MalformedURLException {
        TestTree tt = new TestTree();
        tt.init();
        tt.setVisible(true);
    }
}
class CustomIconRenderer extends DefaultTreeCellRenderer {
    /**
     * 
     */
    private static final long serialVersionUID = 967937360839244309L;
    ImageIcon groupedIcon;
    ImageIcon unGroupedIcon;
    boolean grouped;

    public CustomIconRenderer() {

    }

    public CustomIconRenderer(boolean grouped) throws MalformedURLException {
        this.grouped = grouped;
        URL url=new URL("https://i.stack.imgur.com/wCF8S.png");
        URL url1=new URL("https://i.stack.imgur.com/T5uTa.png");
        groupedIcon = new ImageIcon(url1
                );
        unGroupedIcon = new ImageIcon(url
                );
    }
@Override
    public Component getTreeCellRendererComponent(JTree tree, Object value,
            boolean sel, boolean expanded, boolean leaf, int row,
            boolean hasFocus) {

        super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
                row, hasFocus);

        Object nodeObj = ((DefaultMutableTreeNode) value).getUserObject();
        // check whatever you need to on the node user object
        if (grouped) {
            setIcon(unGroupedIcon);
        } else {
            System.out.println("reached");
            setIcon(groupedIcon);
        }
        return this;
    }
}
User123
  • 71
  • 3
  • 14
  • added runnable correct example – User123 May 13 '15 at 04:26
  • 1) An MCVE needs to be one source file (which can contain more than one non-public class) and include imports. 2) We cannot run it and see the problem without the image files which are on your PC! One way to get image(s) for an example is to **hot link** to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). – Andrew Thompson May 13 '15 at 05:11
  • 1
    Plus one for adding an MCVE. I'm trying to get this re-opened but still need two more open votes. In the mean time, change `public Component getTreeCellRendererComponent(..` to `@Override public Component getTreeCellRendererComponent(..` for a revealing compiler message. – Andrew Thompson May 13 '15 at 08:03
  • *"In for loop odd one nodes have one icon and evens have another."* OK. What exactly do you mean by 'odd'? Are they the ones that have text ending in an odd number? Are the odd ones 'every other one' when adding the nodes? Something else..? – Andrew Thompson May 13 '15 at 11:56
  • odd ones that have text ending in an odd number – User123 May 14 '15 at 04:24

2 Answers2

5

There were a couple of mistakes in the original code, most notably:

  • Setting a cell renderer every time a node was added (a tree can only have a single cell renderer, so the 'last one added' wins).
  • Expecting that the slightly altered method you coded for getting a tree cell renderer would ever be called. (You did do that experiment I proposed in comment, right?)

I think this is more along the lines of the requirement. Note that I was trying to stick as close to the original code as possible. I would approach this differently to how it is seen here.

  • This example: Examines the String value of the value passed to the method to get the cell renderer to see if it contains an _ character, then splits the string and parses the last part back to an integer value.
  • How it should be done: Pass Integer objects for the leaves of the tree. In the cell renderer check of the value is an instance of Integer and if so, prefix the number with node_ ..

enter image description here

import java.awt.*;
import java.net.*;
import javax.swing.*;
import javax.swing.tree.*;

public class TestTree extends JDialog {

    JTree tree;

    DefaultTreeModel treeModel;

    public TestTree() {
        setSize(300, 800);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        System.out.println(getContentPane().getBackground());
    }

    protected static ImageIcon createImageIcon(String path) throws MalformedURLException {
        java.net.URL imgURL = new URL(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }

    public void init() throws MalformedURLException {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Numbers");
        treeModel = new DefaultTreeModel(root);
        tree = new JTree(treeModel);
        tree.setBackground(new Color(238, 238, 244));
        tree.setOpaque(true);

        CustomIconRenderer customIconRenderer = new CustomIconRenderer();
        customIconRenderer.setTextSelectionColor(Color.white);
        customIconRenderer.setBackgroundSelectionColor(Color.blue);
        customIconRenderer.setBorderSelectionColor(Color.black);
        customIconRenderer.setBackgroundNonSelectionColor(new Color(238, 238,
                244));
        ImageIcon icon = createImageIcon("https://i.stack.imgur.com/wCF8S.png");
        customIconRenderer.setLeafIcon(icon);
        tree.setCellRenderer(new CustomIconRenderer());

        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0) {
                DefaultMutableTreeNode subroot = new DefaultMutableTreeNode(
                        "node_" + i);
                root.add(subroot);

                if (i % 3 == 0) {
                    for (int j = 10; j < 15; j++) {
                        DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(
                                "node_" + j);
                        subroot.add(leaf);
                    }
                }
            } else {
                DefaultMutableTreeNode subroot = new DefaultMutableTreeNode(
                        "node_" + i);
                root.add(subroot);
                if (i % 4 == 0) {
                    for (int j = 15; j < 20; j++) {
                        DefaultMutableTreeNode leaf = new DefaultMutableTreeNode(
                                "node_" + j);
                        subroot.add(leaf);
                    }
                }
            }
        }

        for (int i = 0; i < tree.getRowCount(); i++) {
            tree.expandRow(i);
        }

        tree.setCellRenderer(customIconRenderer);

        getContentPane().add(tree, BorderLayout.CENTER);
    }

    public static void main(String args[]) throws MalformedURLException {
        TestTree tt = new TestTree();
        tt.init();
        tt.setVisible(true);
    }
}

class CustomIconRenderer extends DefaultTreeCellRenderer {

    /**
     *
     */
    private static final long serialVersionUID = 967937360839244309L;
    ImageIcon groupedIcon;
    ImageIcon unGroupedIcon;

    public CustomIconRenderer() throws MalformedURLException {
        URL url = new URL("https://i.stack.imgur.com/wCF8S.png");
        URL url1 = new URL("https://i.stack.imgur.com/T5uTa.png");
        groupedIcon = new ImageIcon(url1);
        unGroupedIcon = new ImageIcon(url);
    }

    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value,
            boolean sel, boolean expanded, boolean leaf, int row,
            boolean hasFocus) {

        super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
                row, hasFocus);

        Object nodeObj = ((DefaultMutableTreeNode) value).getUserObject();
        String s = nodeObj.toString();
        System.out.println("s: " + s);
        boolean includesUnderscore = s.indexOf("_") > 0;
        if (includesUnderscore) {
            String lastPart = s.split("_")[1];
            int num = Integer.parseInt(lastPart);
            // check whatever you need to on the node user object
            if (num % 2 == 0) {
                setIcon(unGroupedIcon);
            } else {
                System.out.println("reached");
                setIcon(groupedIcon);
            }
        }
        return this;
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • In my application populating tree nodes from db and set icon based on different conditions correspond to each level of nodes.In that case I want to pass one flag to CustomRenderer class. can I define another function in render class and set global variable value. – User123 May 14 '15 at 06:01
  • 1
    *"can I define another function in render class and set global variable value."* I don't really think you understand that there is only ***ever*** a single cell renderer, no matter how many tree nodes exist. Do you understand that? BTW - to me 'global' means the same value for all cell renderers (no matter how many there are) so it does not really make sense to be trying to use a global variable to have different leaves rendered differently. One of us is very confused, I wish I knew which one! – Andrew Thompson May 14 '15 at 06:06
  • Thanks Andrew .applied on my application and got it. – User123 May 14 '15 at 06:43
  • Glad you got it sorted. :) – Andrew Thompson May 14 '15 at 06:44
1

I created a customTreeCellRender.But not changing the icon

You do not need to call getTreeCellRendererComponent directly, rather let the JTree handle it by explicitly setting the TreeCellRenderer for the JTree as outlined in the Oracle tutorial

tree.setCellRenderer(customIconRenderer);
mKorbel
  • 109,525
  • 20
  • 134
  • 319
copeg
  • 8,290
  • 19
  • 28
  • above mensioned tutorial set same icon for all nodes.But I want to set different icons for each node.I am not directly calling getTreeCellRendererComponent ,its one of the methods in CustomRender class.Instead of invoking consructor I used this method.Please note the number of parameters passed during the method call. – User123 May 13 '15 at 04:25