How do I create JTree with different icons for each node?

The example below demonstrates you how to create a JTree that have a different icons for each node of the tree.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
import java.awt.*;
import java.net.URL;

public class JTreeDifferentNodeIcon extends JFrame {
    public JTreeDifferentNodeIcon() throws HeadlessException {
        initializeUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(
                () -> new JTreeDifferentNodeIcon().setVisible(true));
    }

    private void initializeUI() {
        setSize(200, 400);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Countries");
        DefaultMutableTreeNode asia = new DefaultMutableTreeNode("Asia");
        Country[] countries = new Country[]{
                new Country("India", "/flags/in.png"),
                new Country("Singapore", "/flags/sg.png"),
                new Country("Indonesia", "/flags/id.png"),
                new Country("Vietnam", "/flags/vn.png"),
        };

        for (Country country : countries) {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(country);
            asia.add(node);
        }

        DefaultMutableTreeNode northAmerica = new DefaultMutableTreeNode("North America");
        countries = new Country[]{
                new Country("United States", "/flags/us.png"),
                new Country("Canada", "/flags/ca.png")
        };

        for (Country country : countries) {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(country);
            northAmerica.add(node);
        }

        DefaultMutableTreeNode southAmerica = new DefaultMutableTreeNode("South America");
        countries = new Country[]{
                new Country("Brazil", "/flags/br.png"),
                new Country("Argentina", "/flags/ar.png"),
                new Country("Uruguay", "/flags/uy.png")
        };
        for (Country country : countries) {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(country);
            southAmerica.add(node);
        }

        DefaultMutableTreeNode europe = new DefaultMutableTreeNode("Europe");
        countries = new Country[]{
                new Country("United Kingdom", "/flags/gb.png"),
                new Country("Germany", "/flags/de.png"),
                new Country("Spain", "/flags/es.png"),
                new Country("France", "/flags/fr.png"),
                new Country("Italy", "/flags/it.png")
        };
        for (Country country : countries) {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(country);
            europe.add(node);
        }

        root.add(asia);
        root.add(northAmerica);
        root.add(southAmerica);
        root.add(europe);

        final JTree tree = new JTree(root);
        tree.setCellRenderer(new CountryTreeCellRenderer());
        tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        tree.addTreeSelectionListener(e -> {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
            if (node == null) {
                return;
            }

            Object nodeInfo = node.getUserObject();
            if (node.isLeaf()) {
                Country country = (Country) nodeInfo;
                System.out.println("country = " + country.getName());
            }
        });

        JScrollPane pane = new JScrollPane(tree);
        pane.setPreferredSize(new Dimension(200, 400));

        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(pane, BorderLayout.CENTER);
    }

    static class CountryTreeCellRenderer implements TreeCellRenderer {
        private final JLabel label;

        CountryTreeCellRenderer() {
            label = new JLabel();
        }

        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
                                                      boolean leaf, int row, boolean hasFocus) {
            Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
            if (userObject instanceof Country country) {
                URL imageUrl = getClass().getResource(country.getFlagIcon());
                if (imageUrl != null) {
                    label.setIcon(new ImageIcon(imageUrl));
                }
                label.setText(country.getName());
            } else {
                label.setIcon(null);
                label.setText(value.toString());
            }
            return label;
        }
    }

    static class Country {
        private String name;
        private String flagIcon;

        Country(String name, String flagIcon) {
            this.name = name;
            this.flagIcon = flagIcon;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getFlagIcon() {
            return flagIcon;
        }

        public void setFlagIcon(String flagIcon) {
            this.flagIcon = flagIcon;
        }
    }
}

Here is the result of our program above:

JTree Nodes With Icons

JTree Nodes With Icons

Flag icons by FamFamFam Flag Icons.

How do I expand or collapse all JTree nodes?

This example demonstrates how to use the expand-all and / or collapse-all features in the java.swing.JTree swing component.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeNode;
import java.awt.*;
import java.util.Enumeration;

public class JTreeNodeAutoExpandCollapse extends JFrame {
    public JTreeNodeAutoExpandCollapse() throws HeadlessException {
        initializeUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(
                () -> new JTreeNodeAutoExpandCollapse().setVisible(true));
    }

    private void initializeUI() {
        setSize(400, 400);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
        DefaultMutableTreeNode chapter1 = new DefaultMutableTreeNode("Chapter 1");
        DefaultMutableTreeNode sub1 = new DefaultMutableTreeNode("1.1");
        DefaultMutableTreeNode sub2 = new DefaultMutableTreeNode("1.2");
        DefaultMutableTreeNode sub3 = new DefaultMutableTreeNode("1.3");
        DefaultMutableTreeNode sub31 = new DefaultMutableTreeNode("1.3.1");
        DefaultMutableTreeNode sub32 = new DefaultMutableTreeNode("1.3.2");

        root.add(chapter1);
        chapter1.add(sub1);
        chapter1.add(sub2);
        chapter1.add(sub3);
        sub3.add(sub31);
        sub3.add(sub32);

        final JTree tree = new JTree(root);
        expandTree(tree, false);

        JScrollPane pane = new JScrollPane(tree);
        pane.setPreferredSize(new Dimension(400, 400));

        JPanel buttonPanel = new JPanel(new BorderLayout());
        JButton expandAll = new JButton("Expand All");
        expandAll.addActionListener(e -> expandTree(tree, true));

        JButton collapseAll = new JButton("Collapse All");
        collapseAll.addActionListener(e -> expandTree(tree, false));

        buttonPanel.add(expandAll, BorderLayout.WEST);
        buttonPanel.add(collapseAll, BorderLayout.EAST);

        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(pane, BorderLayout.CENTER);
        getContentPane().add(buttonPanel, BorderLayout.SOUTH);
    }

    private void expandTree(JTree tree, boolean expand) {
        TreeNode root = (TreeNode) tree.getModel().getRoot();
        expandAll(tree, new TreePath(root), expand);
    }

    private void expandAll(JTree tree, TreePath path, boolean expand) {
        TreeNode node = (TreeNode) path.getLastPathComponent();

        if (node.getChildCount() >= 0) {
            Enumeration<? extends TreeNode> enumeration = node.children();
            while (enumeration.hasMoreElements()) {
                TreeNode treeNode = enumeration.nextElement();
                TreePath treePath = path.pathByAddingChild(treeNode);

                expandAll(tree, treePath, expand);
            }
        }

        if (expand) {
            tree.expandPath(path);
        } else {
            tree.collapsePath(path);
        }
    }
}

JTree Expand and Collapse All

How do I remove a node from JTree?

The code below demonstrates how to delete a node from a JTree component.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class JTreeRemoveNode extends JFrame {
    public JTreeRemoveNode() throws HeadlessException {
        initializeUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new JTreeRemoveNode().setVisible(true));
    }

    private void initializeUI() {
        setSize(400, 400);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Address Book");
        String[] names = new String[]{"Alice", "Bob", "Carol", "Mallory"};
        for (String name : names) {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(name);
            root.add(node);
        }

        final JTree tree = new JTree(root);
        JScrollPane pane = new JScrollPane(tree);
        pane.setPreferredSize(new Dimension(400, 400));

        JButton removeButton = new JButton("Remove");
        removeButton.addActionListener(e -> {
            DefaultTreeModel model = (DefaultTreeModel) tree.getModel();

            TreePath[] paths = tree.getSelectionPaths();
            if (paths != null) {
                for (TreePath path : paths) {
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode)
                            path.getLastPathComponent();
                    if (node.getParent() != null) {
                        model.removeNodeFromParent(node);
                    }
                }
            }
        });

        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(tree, BorderLayout.CENTER);
        getContentPane().add(removeButton, BorderLayout.SOUTH);
    }
}

Remove a node from JTree

How do I get the selected nodes of a JTree?

The following example show how to use the JTree.getSelectionPaths() method to get the selected node of a JTree component. This method returns an array of TreePath objects. In the case to get the last node in the path we can call the TreePath.getLastPathComponent().

In the code below when you pressed the button the listener gets the selection paths and print out the last path component of the selected nodes.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;

public class JTreeGetSelectedNode extends JFrame {
    public JTreeGetSelectedNode() throws HeadlessException {
        initializeUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new JTreeGetSelectedNode().setVisible(true));
    }

    private void initializeUI() {
        setSize(500, 500);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Countries");
        DefaultMutableTreeNode asia = new DefaultMutableTreeNode("Asia");
        String[] countries = new String[]{"India", "Singapore", "Indonesia", "Vietnam"};
        for (String country : countries) {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(country);
            asia.add(node);
        }

        DefaultMutableTreeNode northAmerica = new DefaultMutableTreeNode("North America");
        countries = new String[]{"United States", "Canada"};
        for (String country : countries) {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(country);
            northAmerica.add(node);
        }

        DefaultMutableTreeNode southAmerica = new DefaultMutableTreeNode("South America");
        countries = new String[]{"Brazil", "Argetina", "Uruguay"};
        for (String country : countries) {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(country);
            southAmerica.add(node);
        }

        DefaultMutableTreeNode europe = new DefaultMutableTreeNode("Europe");
        countries = new String[]{"United Kingdom", "Germany", "Spain", "France", "Italy"};
        for (String country : countries) {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(country);
            europe.add(node);
        }

        root.add(asia);
        root.add(northAmerica);
        root.add(southAmerica);
        root.add(europe);

        final JTree tree = new JTree(root);
        JScrollPane pane = new JScrollPane(tree);
        pane.setPreferredSize(new Dimension(500, 500));

        JButton button = new JButton("Get Selected");
        button.addActionListener(e -> {
            TreePath[] paths = tree.getSelectionPaths();
            for (TreePath path : paths != null ? paths : new TreePath[0]) {
                System.out.println("You've selected: " + path.getLastPathComponent());
            }
        });

        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(pane, BorderLayout.CENTER);
        getContentPane().add(button, BorderLayout.SOUTH);
    }
}

How do I change JTree default icons?

The program below demonstrate how to change the default icons of a JTree component. We can change tree icons of the component which are the closed icon, the open icon and the leaf icon.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;
import java.util.Objects;

public class JTreeChangeIcon extends JFrame {
    public JTreeChangeIcon() throws HeadlessException {
        intializeUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new JTreeChangeIcon().setVisible(true));
    }

    private void intializeUI() {
        setSize(500, 500);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Address Book");
        DefaultMutableTreeNode a = new DefaultMutableTreeNode("A");
        DefaultMutableTreeNode b = new DefaultMutableTreeNode("B");
        DefaultMutableTreeNode c = new DefaultMutableTreeNode("C");

        DefaultMutableTreeNode aContact = new DefaultMutableTreeNode("Alice");
        DefaultMutableTreeNode bContact = new DefaultMutableTreeNode("Bob");
        DefaultMutableTreeNode cContact = new DefaultMutableTreeNode("Carol");

        root.add(a);
        root.add(b);
        root.add(c);

        a.add(aContact);
        b.add(bContact);
        c.add(cContact);

        JTree tree = new JTree(root);

        // Change the default JTree icons
        DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) tree.getCellRenderer();
        Icon closedIcon = new ImageIcon(Objects.requireNonNull(
                this.getClass().getResource("/images/lightbulb_off.png")));
        Icon openIcon = new ImageIcon(Objects.requireNonNull(
                this.getClass().getResource("/images/lightbulb.png")));
        Icon leafIcon = new ImageIcon(Objects.requireNonNull(
                this.getClass().getResource("/images/lightning.png")));
        renderer.setClosedIcon(closedIcon);
        renderer.setOpenIcon(openIcon);
        renderer.setLeafIcon(leafIcon);

        JScrollPane pane = new JScrollPane(tree);
        pane.setPreferredSize(new Dimension(500, 500));

        getContentPane().add(tree);
    }
}

How do I remove JTree default icons?

You can remove JTree default icons by modifying the tree cell renderer object. To get the cell renderer call the JTree.getCellRenderer() which will return a DefaultTreeCellRenderer object. Then you can remove the icon by setting a null value to the setLeafIcon(), setClosedIcon() and setOpenIcon().

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;

public class JTreeRemoveIcon extends JFrame {
    public JTreeRemoveIcon() throws HeadlessException {
        initializeUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new JTreeRemoveIcon().setVisible(true));
    }

    private void initializeUI() {
        setSize(500, 500);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Address Book");
        DefaultMutableTreeNode a = new DefaultMutableTreeNode("A");
        DefaultMutableTreeNode b = new DefaultMutableTreeNode("B");
        DefaultMutableTreeNode c = new DefaultMutableTreeNode("C");

        DefaultMutableTreeNode aContact = new DefaultMutableTreeNode("Alice");
        DefaultMutableTreeNode bContact = new DefaultMutableTreeNode("Bob");
        DefaultMutableTreeNode cContact = new DefaultMutableTreeNode("Carol");

        root.add(a);
        root.add(b);
        root.add(c);

        a.add(aContact);
        b.add(bContact);
        c.add(cContact);

        JTree tree = new JTree(root);

        // Remove default JTree icons
        DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) tree.getCellRenderer();
        renderer.setLeafIcon(null);
        renderer.setClosedIcon(null);
        renderer.setOpenIcon(null);

        JScrollPane pane = new JScrollPane(tree);
        pane.setPreferredSize(new Dimension(200, 400));

        getContentPane().add(tree);
    }
}
Remove JTree Default Icon

Remove JTree Default Icon

How do I add selection listener to JTree?

This example shows you how to use the TreeSelectionListener to add a tree selection listener to the JTree component. In the listener method below you can see how to get the selected path and print out the selected path to the console.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;

public class JTreeSelectionListenerDemo extends JFrame {

    public JTreeSelectionListenerDemo() throws HeadlessException {
        initializeUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(
                () -> new JTreeSelectionListenerDemo().setVisible(true));
    }

    private void initializeUI() {
        setSize(500, 500);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
        DefaultMutableTreeNode chapterOne = new DefaultMutableTreeNode("Chapter One");
        DefaultMutableTreeNode one = new DefaultMutableTreeNode("1.1");
        DefaultMutableTreeNode two = new DefaultMutableTreeNode("1.2");
        DefaultMutableTreeNode three = new DefaultMutableTreeNode("1.3");

        root.add(chapterOne);
        chapterOne.add(one);
        chapterOne.add(two);
        chapterOne.add(three);

        JTree tree = new JTree(root);
        tree.addTreeSelectionListener(e -> {
            TreePath path = e.getPath();
            int pathCount = path.getPathCount();

            for (int i = 0; i < pathCount; i++) {
                System.out.print(path.getPathComponent(i).toString());
                if (i + 1 != pathCount) {
                    System.out.print(" | ");
                }
            }
            System.out.println();
        });

        JScrollPane pane = new JScrollPane(tree);
        pane.setPreferredSize(new Dimension(200, 400));

        getContentPane().add(pane);
    }
}

How do I change color of selected node in JTree?

This example show you how to change the color of the selected node of the JTree component. It shows you how to set the node background color, the font color and the selected node border color.

To do this you need to obtain the DefaultTreeCellRenderer object from the JTree instance and modified the selection color of the node.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;

public class JTreeTextSelectionColorDemo extends JFrame {
    public JTreeTextSelectionColorDemo() throws HeadlessException {
        initializeUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(
                () -> new JTreeTextSelectionColorDemo().setVisible(true));
    }

    private void initializeUI() {
        setSize(500, 500);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Department");
        DefaultMutableTreeNode book = new DefaultMutableTreeNode("Books");
        DefaultMutableTreeNode fiction = new DefaultMutableTreeNode("Fictions");
        DefaultMutableTreeNode science = new DefaultMutableTreeNode("Sciences");
        DefaultMutableTreeNode text = new DefaultMutableTreeNode("Text Books");
        DefaultMutableTreeNode children = new DefaultMutableTreeNode("Children");

        root.add(book);
        book.add(fiction);
        book.add(science);
        book.add(text);
        book.add(children);

        JTree tree = new JTree(root);

        // Get the DefaultTreeCellRenderer instance of the JTree
        // component. Then we customize the color of the selection
        // node using blue background, white font color and black
        // border.
        DefaultTreeCellRenderer renderer =
                (DefaultTreeCellRenderer) tree.getCellRenderer();
        renderer.setTextSelectionColor(Color.white);
        renderer.setBackgroundSelectionColor(Color.blue);
        renderer.setBorderSelectionColor(Color.red);

        JScrollPane pane = new JScrollPane(tree);
        pane.setPreferredSize(new Dimension(250, 350));

        getContentPane().add(pane);
    }
}
JTree Node Color Demo

JTree Node Color Demo

How do I use a JTree component?

The example introduce you how to use the JTree swing component to create a presentation of hierarchical data. The hierarchical data can be viewed in expand mode or collapse mode.

To create an item of the tree we create an instance of DefaultMutableTreeNode which located in the javax.swing.tree package. This class implements the TreeNode and MutableTreeNode interfaces. Mutable means that the node can be changed. It can be added new children node or deleted children node from their parent node.

Below we create a tree component to display information about week day names and the month names. The Root node have the Days and Months. The Days node contains a week day names and the Months node contains the month names.

package org.kodejava.swing;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
import java.text.DateFormatSymbols;

public class JTreeDemo extends JFrame {
    public JTreeDemo() {
        initializeUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new JTreeDemo().setVisible(true));
    }

    private void initializeUI() {
        setSize(500, 500);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLayout(new FlowLayout(FlowLayout.LEFT));

        // Creating tree node of day names.
        DefaultMutableTreeNode day = new DefaultMutableTreeNode("Days");
        DefaultMutableTreeNode sun = new DefaultMutableTreeNode("Sunday");
        DefaultMutableTreeNode mon = new DefaultMutableTreeNode("Monday");
        DefaultMutableTreeNode tue = new DefaultMutableTreeNode("Tuesday");
        DefaultMutableTreeNode wed = new DefaultMutableTreeNode("Wednesday");
        DefaultMutableTreeNode thu = new DefaultMutableTreeNode("Thursday");
        DefaultMutableTreeNode fri = new DefaultMutableTreeNode("Friday");
        DefaultMutableTreeNode sat = new DefaultMutableTreeNode("Saturday");

        // Adding the day nodes into day tree node.
        day.add(sun);
        day.add(mon);
        day.add(tue);
        day.add(wed);
        day.add(thu);
        day.add(fri);
        day.add(sat);

        // Creates tree node of month names using a for loop where the
        // month names is obtained using the DateFormatSymbols class.
        DefaultMutableTreeNode month = new DefaultMutableTreeNode("Months");
        String[] months = DateFormatSymbols.getInstance().getMonths();
        for (String monthName : months) {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(monthName);
            month.add(node);
        }

        // Creating a root node for our JTree and add day and month items
        // to the tree.
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
        root.add(day);
        root.add(month);

        // Creating an instance of JTree using the instance of
        // DefaultMutableTreeNode. We also create a scroll pane for our
        // tree container.
        JTree tree = new JTree(root);
        JScrollPane pane = new JScrollPane(tree);
        pane.setPreferredSize(new Dimension(250, 450));
        getContentPane().add(pane);
    }
}
Swing JTree Demo

Swing JTree Demo