Share this page 

Use a JTree to navigate in a siteTag(s): Swing


This How-to will show you how to build a Tree (like this one) using Swing.

NOTE: This Tree Applet is different since it's plain JDK1.0.2 Applet.

First, we define the class representing a node. This node contains a title (the label), a URL, 2 icons (open and close).

import javax.swing.*;

public class RealSwingNode extends Object {
  private String _title;
  private String _link;
  private ImageIcon  _openedIcon;
  private ImageIcon  _closedIcon;

  RealSwingNode
     (String title, String link, ImageIcon closed, ImageIcon opened) {
    _title = title;
    _link = link;
    _openedIcon = opened;
    _closedIcon = closed;
    }

  String getTitle()  { return _title; }
  String getLink()   { return _link; }
  ImageIcon  getOpenedIcon() { return _openedIcon; }
  ImageIcon  getClosedIcon() { return _closedIcon; }
  public String toString()  { return _title; }
  }
Then we define how the node would be shown in the Tree. This is done by implementing a Renderer class.
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;

public class RealSwingTreeIconRenderer extends Object
      implements TreeCellRenderer {
  JLabel _label;

  RealSwingTreeIconRenderer() {
    _label = new JLabel();
    _label.setOpaque(true);
    }

  public Component getTreeCellRendererComponent
      (JTree tree, Object value, boolean selected,
       boolean expanded, boolean leaf, int row, boolean hasFocus) {
    RealSwingNode _userObject = null;

    _label.setFont(tree.getFont());

    if (selected){
       _label.setForeground(tree.getBackground());
       _label.setBackground(tree.getForeground());
       }
    else {
       _label.setBackground(tree.getBackground());
       _label.setForeground(tree.getForeground());
       }

    if (value instanceof RealSwingNode) {
       _userObject = (RealSwingNode) value;
       }
    else if(value instanceof DefaultMutableTreeNode) {
       DefaultMutableTreeNode node;

       node = (DefaultMutableTreeNode) value;

       if (node.getUserObject() instanceof RealSwingNode) {
         _userObject = (RealSwingNode) node.getUserObject();
         }
       }


    if(_userObject != null) {
      if (expanded)
          _label.setIcon(_userObject.getOpenedIcon());
      else
          _label.setIcon(_userObject.getClosedIcon());
       _label.setText(_userObject.getTitle());
       }
    else {
       _label.setIcon(null);
       _label.setText(value.toString());
        }

    return _label;
    }
}
The next step is building the JTree in a JPanel. We use a datafile to define the Tree nodes. Since this Tree is designed to be used in Applet, we must pass a JApplet reference to be able to read some parameters passed via the HTML PARAM tags.
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;
import java.net.*;
import java.io.*;

public class RealSwingTree extends JPanel
  implements TreeSelectionListener {
 private JApplet parentApplet;
 private JTree tree;
 private Font f;
 private ImageIcon treeIcons[];
 private String targetFrame;

 public RealSwingTree() {
 System.out.println(System.getProperty("os.name"));
  try {
    UIManager.setLookAndFeel(
      UIManager.getSystemLookAndFeelClassName());
    }
  catch (Exception ex_ignored) {
     ex_ignored.printStackTrace();
     }
  }

 public void setParentApplet(JApplet j) {
   parentApplet = j;
   }

 public void initTree() {
   // build the tree from the datafile
   DefaultMutableTreeNode rootNode = null;
   DefaultMutableTreeNode currentNode = null;
   DefaultMutableTreeNode node = null;
   RealSwingNode rsn = null;
   RealSwingTreeIconRenderer rstir;
   TreeSelectionModel tsm;

   int token, value=0, oldvalue=0, rootvalue=0, image1idx=0, image2idx=0;
   String strValue, lnkValue, imageValue;
   boolean rootDone=false;
   boolean itemDone=true;
   System.out.println("[RealSwingTree] Begin populateTree() " );
   try {

    initTreeIcons();
    targetFrame = parentApplet.getParameter("targetframe");

    URL urlFile =
       new URL(parentApplet.getCodeBase(),
           parentApplet.getParameter("datafile"));

    Reader r = new BufferedReader
       (new InputStreamReader(urlFile.openStream()));
    StreamTokenizer st = new StreamTokenizer(r);

    st.quoteChar('"');
    st.eolIsSignificant(false);
    st.parseNumbers();
    //
    // datafile structure <level> <label> <link> <image1> <image2>
    //
    while ((token = st.nextToken()) != StreamTokenizer.TT_EOF ) {
      // get level
      value = new  Double(st.nval).intValue();
      if (!rootDone) {
         // do the root first
         token = st.nextToken();
         strValue = st.sval;
         token = st.nextToken();
         lnkValue = st.sval;
         rsn = new RealSwingNode(strValue, "", null, null);
         node = new DefaultMutableTreeNode(rsn, true);
         rootNode = node;
         rootDone = true;
         }
      else {
         token = st.nextToken(); strValue = st.sval;
         token = st.nextToken(); lnkValue = st.sval;
         token = st.nextToken(); image1idx = Integer.parseInt(st.sval);
         token = st.nextToken(); image2idx = Integer.parseInt(st.sval);
         rsn = new RealSwingNode
           (strValue, lnkValue, treeIcons[image1idx], 
              treeIcons[image2idx]);
         node = new DefaultMutableTreeNode(rsn, true);
         if (value >= oldvalue) {
            if (value==oldvalue) {
               // *** sibling
               if (currentNode.equals(rootNode))
                  rootNode.add(node);
               else {
                  DefaultMutableTreeNode dmtn =
                   (DefaultMutableTreeNode)currentNode.getParent();
                  dmtn.add(node);
                  }
               }
            else {
               // *** child
               currentNode.add(node);
               }
           }
         else {
           // *** new branch, must get back to the right level
           while (value < oldvalue) {
              currentNode = 
                  (DefaultMutableTreeNode)currentNode.getParent();
              oldvalue--;
              }
           DefaultMutableTreeNode dmtn =
             (DefaultMutableTreeNode)currentNode.getParent();
           if (dmtn.equals(rootNode))
               rootNode.add(node);
            else
               dmtn.add(node);
            }
         }
         currentNode = node;
         oldvalue = value;
     }

     tree = new JTree(rootNode);
     Color bgcolor = new Color(
     Integer.valueOf
       (parentApplet.getParameter("bgcolor"), 16).intValue());
     setBackground(bgcolor);
     Font f = new Font
       (parentApplet.getParameter("font"),
        Font.PLAIN,
        Integer.parseInt(parentApplet.getParameter("point")));
     setFont(f);
     setLayout(new BorderLayout());
     tree.setRootVisible(true);
     tree.setShowsRootHandles(true);

     tree.addTreeSelectionListener(this);
     tsm = tree.getSelectionModel();
     tsm.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

     rstir = new RealSwingTreeIconRenderer();
     tree.setCellRenderer(rstir);
     tree.setRowHeight(0);

     add(new JScrollPane(tree),"Center");
     }

   catch (Exception e) {e.printStackTrace(); }
   System.out.println("[RealSwingTree] End populatetree()");
  }


public void initTreeIcons() {
  String rootImage;
  String pathImages;
  String leaveImagesList;
  Vector leaveImage = new Vector();

  rootImage = parentApplet.getParameter("rootimage");
  pathImages = parentApplet.getParameter("images");
  leaveImagesList = parentApplet.getParameter("leaveimageslist");

  System.out.println("begin initImage()");

  StringTokenizer leavesList =
         new StringTokenizer(leaveImagesList, ",");
  while(leavesList.hasMoreTokens()){
    String s=leavesList.nextToken();
    leaveImage.addElement(s);
    }

 treeIcons = new ImageIcon[leaveImage.size()];

 for(int i=0; i < leaveImage.size(); i++) {
    try {
      URL imageURL = new URL
       (parentApplet.getCodeBase() + "/" + pathImages
        + "/" + (String)leaveImage.elementAt(i));
      treeIcons[i] = new ImageIcon(imageURL);
      System.out.println("Loading ..." + (String)leaveImage.elementAt(i));
      }
    catch(Exception e) { e.printStackTrace(); }
    }

 System.out.println("end initImage()");
}

public void valueChanged(TreeSelectionEvent tse) {
  DefaultMutableTreeNode dmtn;
  RealSwingNode rsn;
  TreePath path = tree.getSelectionPath();

  if (path != null) {
    dmtn = (DefaultMutableTreeNode) path.getLastPathComponent();
    rsn = (RealSwingNode)dmtn.getUserObject();
    System.out.println("Click! link: " + rsn.getLink());
    if (!rsn.getLink().equals("")) {
       try {
         URL newURL = new URL
            (parentApplet.getCodeBase() + rsn.getLink());
         System.out.println("       url: " + newURL.toString()
               + " target:" +targetFrame);
         parentApplet.getAppletContext().showDocument
           (newURL,targetFrame);
         }
       catch (Exception e) {
         e.printStackTrace();
         }
       }
    }
  }

public Dimension getPreferredSize() {
  return new Dimension(250, 400);
  }
}
Let's make a simple Applet to try it out.
import javax.swing.*;
import java.awt.*;


public class RealSwingTreeApplet extends JApplet {
  RealSwingTree rst;

  public void init() {
   rst = new RealSwingTree();
   rst.setParentApplet(this);
   rst.initTree();
   getContentPane().add(rst);
  }
}
Here a sample datafile. The structure is "[level] [label] [link] [image1] [image2]". The image number is the index of the image passed via the PARAM leaveimageslist.

[treedata.txt]

0  "Welcome | Bienvenue" "welcome.html"
0 "Java How-to" "" "0" "1"
     1 "What's new" "java-new.html" "2" "2"
     1 "General" "" "0" "1"
       2 "part 1" "java-g1.html" "2" "2"
Here the HTML used to test the Tree. Since there is almost no error checking, all PARAM tags are required.
<HTML><BODY>
<APPLET CODE="RealSwingTreeApplet.class"
        NAME="RealTree"
        HEIGHT=2000 WIDTH=196>
<PARAM NAME="datafile"  VALUE="treedata.txt">
<PARAM NAME="bgcolor" VALUE="FFFFFF">
<PARAM NAME="font" VALUE="Courier">
<PARAM NAME="point" VALUE="11">
<PARAM NAME="images" VALUE="./images">
<PARAM NAME="targetframe" VALUE="_top">
<PARAM NAME="rootimage" VALUE="root.gif">
<PARAM NAME="leaveimageslist"
    VALUE="fclose.jpg,fopen.jpg,page.jpg">
</APPLET></BODY></HTML>
The <APPLET> tag and Swing applet are ok with Appletviewer, but in most browser, you need to execute the Applet under the Java plugin. Therefore, you need to use the <EMBED> tag with Netscape or <OBJECT> tag with IE. So for example, with Netscape, the HTML will be like this :
<HTML><BODY>
<EMBED type="application/x-java-applet;version=1.2.2" width="200"
    height="2000" code="RealSwingTreeApplet.class"
    datafile="treedata.txt"
    bgcolor="FFFFFF"
         ... other params here ...

 pluginspage="http://java.sun.com/products/plugin/1.2/plugin-install.html">
 <NOEMBED>
    No JDK 1.2 support for APPLET!!
 </NOEMBED>
</EMBED>
</BODY></HTML>
Finally, you may want to grab these images used in this How-to .

root.gif fclose.jpg fopen.jpg fpage.jpg