This article explains working with JTree and proceeds to show some examples.

We will write code to achieve a JTree output like:

JTree with Custom Image Icon

Output


Table of Contents:

1.Introduction

2.Developing a Simple JTree

3.Adding More Children

4.Customizing Tree's Display

5.Adding a Scrollpane

6.Showing Root Handles

7.Hiding Root Node

8.Changing Visual Icons

9.Event Handlers

 

1. Introduction to JTree:

JTree is a Swing component with which we can display hierarchical data. JTree is quite a complex component. A JTree has a 'root node' which is the top-most parent for all nodes in the tree. A node is an item in a tree. A node can have many children nodes. These children nodes themselves can have further children nodes. If a node doesn't have any children node, it is called a leaf node.

The leaf node is displayed with a different visual indicator. The nodes with children are displayed with a different visual indicator along with a visual 'handle' which can be used to expand or collapse that node. Expanding a node displays the children and collapsing hides them.

 

2. Developing a Simple JTree:

 Let us now attempt to build a simple JTree. Let us say we want to display the list of vegetables and fruits hierarchically.

The node is represented in Swing API as TreeNode which is an interface. The interface MutableTreeNode extends this interface which represents a mutable node. Swing API provides an implementation of this interface in the form of DefaultMutableTreeNode class.

We will be using the DefaultMutableTreeNode class to represent our node. This class is provided in the Swing API and we can use it to represent our nodes. This class has a handy add() method which takes in an instance of MutableTreeNode.

So, we will first create the root node. And then we can recursively add nodes to that root. Let us start with a simple root with just 2 nodes:

package net.codejava.swing;
import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
public class TreeExample extends JFrame
{
    private JTree tree;
    public TreeExample()
    {
        //create the root node
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
        //create the child nodes
        DefaultMutableTreeNode vegetableNode = new DefaultMutableTreeNode("Vegetables");
        DefaultMutableTreeNode fruitNode = new DefaultMutableTreeNode("Fruits");
        //add the child nodes to the root node
        root.add(vegetableNode);
        root.add(fruitNode);
        
        //create the tree by passing in the root node
        tree = new JTree(root);
        add(tree);
        
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("JTree Example");        
        this.pack();
        this.setVisible(true);
    }
    
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TreeExample();
            }
        });
    }        
}
As explained earlier, we create a root node and add child nodes to it. Note that, when we create the JTree instance, we just pass the root node instance. This is because, the root node contains all the information including the children.



Let us now run the program:

JTree Output with 2 children

Initial Output with two Children


The output shows the root node and the two children. Note the difference in the icon that is displayed prior to the text. The nodes which have children are indicated with a folder icon and the leaf nodes are displayed with a different icon.

 


3. Adding More Children to JTree

Let us now add more children to the vegetable and fruits node. This is very simple. We just need to add DefaultMutableTreeNode instances to the vegetableNode and the fruitNode instance, like:

DefaultMutableTreeNode vegetableNode = new DefaultMutableTreeNode("Vegetables");
vegetableNode.add(new DefaultMutableTreeNode("Capsicum"));
vegetableNode.add(new DefaultMutableTreeNode("Carrot"));
vegetableNode.add(new DefaultMutableTreeNode("Tomato"));
vegetableNode.add(new DefaultMutableTreeNode("Potato"));
DefaultMutableTreeNode fruitNode = new DefaultMutableTreeNode("Fruits");
fruitNode.add(new DefaultMutableTreeNode("Banana"));
fruitNode.add(new DefaultMutableTreeNode("Mango"));
fruitNode.add(new DefaultMutableTreeNode("Apple"));
fruitNode.add(new DefaultMutableTreeNode("Grapes"));
fruitNode.add(new DefaultMutableTreeNode("Orange"));

When we run the program, we get the following output:


JTree Collapsed Parent Nodes

More Children Added


We can see that the icon displayed for the 'Vegetables' and 'Fruits' node has changed from a leaf icon to a folder icon. This indicates that these nodes have children themselves now. Also, note the handler icon (the one that looks like a key) that is displayed besides these nodes. These can be clicked on to expand the nodes.


Let us now run the program again and click on both these handles to expand them. We get the following output:


JTree Expanded Parent Nodes

Expanded Tree


Once we expand the nodes, we can see all the items in the tree displayed in a nice hierarchical structure. Also note that the handler is shown with a different indicator icon.

 

  

4. Customizing JTree's Display:

Let us now try and customize a JTree's display. Let us now run the program again and click on the handles. Then, resize the frame to use less height. We will get the following output:


JTree without Scrollpane

Tree without Scrollbars


As we can see, when the frame is resized, the items are hidden. Instead, we would

want to display a scrollbar and allow the user to scroll up and down to see the entire tree data.

 


5. Adding a Scrollpane for JTextField

Doing this is very simple. Like many other Swing components, we just need to wrap our tree within a JScrollPane and add it to the frame. Instead of adding the tree to the frame, we add the scrollpane, like:


add(new JScrollPane(tree));


Let us now run the program again, click on the handler icons to expand the nodes and resize the frame. We will get an output like this:


JTree with Scrollpane

Tree with Scrollbars


We can see that now a scrollbar is added and we can scroll to see the nodes. Now, try and collapse one of the nodes. We can see that the scrollbar disappears. The scroll bar appears when it has items beyond the display area.


6. Showing Root Handles for JTree:

When you have a close look at the output again, we see that the 'Vegetables' and 'Fruits' nodes have the 'handler' icon, but the 'Root' node doesn't. The root node is the parent of all nodes, so, it would be possible for us to expand and collapse this too. If you double-click on the root node, you can actually collapse and expand it. However, this is not very convenient and consistent with the rest of the tree.


So, let us now try and display the handle for the root node. This can be done with a simple API call such as:


tree.setShowsRootHandles(true);


Let us now run the program again. We can see that the root handle is shown:


JTree with Root Handles

Tree with Root Handles Displayed


7. Hiding Root Node of JTree

The root node is the topmost in the hierarchy. However, the display of root node may not be needed in some cases. For example, we have been using a root node displayed with the text 'Root'. This is not very useful. So, what if we want to hide it? This is possible with a simple API call:


tree.setRootVisible(false);


Let us now run the program. We get the following when the trees are expanded:


JTree Root Node Hidden

Tree with Root Node Hidden

Note that we still make the call to tree.setShowsRootHandles(true) as otherwise we will not see the root handles for the 'Vegetables' and 'Fruits' node.

 

 

8. Changing the Visual Icons for JTree

JTree uses different icons to represent leaf node and nodes with children as we have seen above. What if we need to provide our own icons for this purpose? It is very much possible. We need to make use of the renderer to do this.


JTree Rendering:

JTree delegates the display of its items to Renderers. By default, a renderer is automatically created for a JTree to display all its items. The rendering is represented by an interface called TreeCellRenderer. The Swing API provides a default implementation of this interface known as DefaultTreeCellRenderer. This class has some handy methods which we can use to customize the display.


Using the DefaultTreeCellRenderer:

We will be creating an instance of DefaultTreeCellRenderer class and using the method setLeafIcon() to set the icon for all our leaf nodes. This method takes an instance of ImageIcon class. The ImageIcon class is used to handle the display of images. So, we will first create an ImageIcon instance and then use it with the renderer:

 

ImageIcon imageIcon = new ImageIcon(TreeExample.class.getResource("/leaf.jpg"));
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
renderer.setLeafIcon(imageIcon);
 

The first line uses the standard mechanism to load images where the image is part of the application (packaged within the jar). Then we create a DefaultTreeCellRenderer instance and call the setLeafIcon() method by passing in this ImageIcon instance. Let us now run the program and expand the nodes to see the image being used for the leaf nodes.

JTree with Custom Image Icon

Tree with Custom Image Icon for Leaf Nodes

 

 

 

9. Set Event Handlers for JTree

Let us now try and develop event handlers for tree. Knowing the currently selected node will be one of the most useful events to know. Event handling in JTree is very similar to that of other Swing components. We register an event listener and are notified when the event happens.

Developing a SelectionListener:

We need to add a TreeSelectionListener to listen for selection events. This is an interface defined in Swing API and we need to implement the valueChanged() method. The source of the selection is passed as a parameter to this method.


The selection in JTree is handled by a class called TreeSelectionModel. So, the JTree delegates all the selection related work to this class.


We will first add a JLabel to be displayed at the bottom. Whenever a node in the tree is selected, we will display the path of the selected node.


Let us first declare a JLabel instance variable:

private JLabel selectedLabel;


We will then add it to the bottom of the frame:

selectedLabel = new JLabel();

add(selectedLabel, BorderLayout.SOUTH);


We will then add the selection listener as follows:

 

tree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
    @Override
    public void valueChanged(TreeSelectionEvent e) {
        selectedLabel.setText(e.getPath().toString());
    }
});
 

We add a selection listener to the tree selection model. The TreeSelectionListener has one method which we implement. We use the event source to invoke the getPath() method and set it to the label that we added earlier. When we run the program, we get the following output:


JTree Selection Path

 

Adding a Selection Listener


An even better usage of the selection listener would be to get the selected node and make use of it. To get the selected node, we can make use of the getLastSelectedPathComponent() method of JTree. This method returns the selected node. We can then invoke the getUserObject() method on the DefaultMutableTreeNode class which returns the actual object we added. Since this method returns an Object instance, we need to call the toString() method on it and add it to the label. We can modify the code as follows:

 

tree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
    @Override
    public void valueChanged(TreeSelectionEvent e) {
        DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
        selectedLabel.setText(selectedNode.getUserObject().toString());
    }
});
 

When we run the program and select a leaf node, we get the following output:

JTree Selected Node

 

Selection Listener to get the Selected Node


Here is the full source code of our GUI:
package net.codejava.swing;
import java.awt.BorderLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer; 
/**
 * JTree basic tutorial and example
 * @author wwww.codejava.net
 */
public class TreeExample extends JFrame
{
    private JTree tree;
    private JLabel selectedLabel;
    
    public TreeExample()
    {
        //create the root node
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
        //create the child nodes
        DefaultMutableTreeNode vegetableNode = new DefaultMutableTreeNode("Vegetables");
        vegetableNode.add(new DefaultMutableTreeNode("Capsicum"));
        vegetableNode.add(new DefaultMutableTreeNode("Carrot"));
        vegetableNode.add(new DefaultMutableTreeNode("Tomato"));
        vegetableNode.add(new DefaultMutableTreeNode("Potato"));
        
        DefaultMutableTreeNode fruitNode = new DefaultMutableTreeNode("Fruits");
        fruitNode.add(new DefaultMutableTreeNode("Banana"));
        fruitNode.add(new DefaultMutableTreeNode("Mango"));
        fruitNode.add(new DefaultMutableTreeNode("Apple"));
        fruitNode.add(new DefaultMutableTreeNode("Grapes"));
        fruitNode.add(new DefaultMutableTreeNode("Orange"));
        //add the child nodes to the root node
        root.add(vegetableNode);
        root.add(fruitNode);
        
        //create the tree by passing in the root node
        tree = new JTree(root);
        ImageIcon imageIcon = new ImageIcon(TreeExample.class.getResource("/leaf.jpg"));
        DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();        
        renderer.setLeafIcon(imageIcon);
        
        tree.setCellRenderer(renderer);
        tree.setShowsRootHandles(true);
        tree.setRootVisible(false);
        add(new JScrollPane(tree));
        
        selectedLabel = new JLabel();
        add(selectedLabel, BorderLayout.SOUTH);
        tree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent e) {
                DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
                selectedLabel.setText(selectedNode.getUserObject().toString());
            }
        });
        
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("JTree Example");        
        this.setSize(200, 200);
        this.setVisible(true);
    }
    
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TreeExample();
            }
        });
    }        
}
 

Other Java Swing Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (JTree_Sample.zip)JTree_Sample.zip[Source code and executable jar file]5 kB

Add comment

   


Comments 

#16Derli Ferreira2020-05-24 11:57
Quoting ToniSun:
tree.setCellRenderer(renderer);

is missing
Thank you for sharing that line!!
Quote
#15phuongtung2018-05-06 11:24
Thank you so much! I'm researching them, and you help me a lot!
Quote
#14sarat2017-05-09 00:43
USEFUL PROGRAM FOR JAVA DEVELOPERS LIKE ME. EXPECT SUCH PROGRAMS IN FUTURE
Quote
#13Tharindu Sathischand2016-11-02 20:19
Very helpful. It helped me to undrtstand this api easily from here, when java docs didn't teached me with such a quality
Quote
#12ToniSun2016-09-22 03:54
tree.setCellRenderer(renderer);

is missing
Quote