CSC 220 Java Swing Unit
Spring 2004
Judy Franklin

Excerpts from How to Use Trees
http://java.sun.com/docs/books/tutorial/uiswing/components/tree.html


Swing's JTree class:


Like any non-trivial Swing component, the tree gets data by querying its data model.
(Model-Delegate Architecture)


  • Node (one row): displays one item of data
  • Every tree has a root node.
  • Branch Nodes: nodes that can have children
  • Leaf Nodes: Nodes that can't have children
  • Users expand or collapse Branch Nodes by clicking
  • TreeExpansionListener or Tree-Will-ExpandListener reacts to expansion events.
  • TreeSelectionListener reacts to selection events




  • TreeDemo.java Example


    • Creates a JSplitPane
    • Creates a JTree, and places it in a JScrollPane
    • Places the JScrollPane in the top half of the JSplitPane
    • Displays Descriptive text, from html files, in the bottom half

    public class TreeDemo extends JPanel implements TreeSelectionListener {
        private JEditorPane htmlPane;
        private JTree tree;
        private URL helpURL;
        private static boolean DEBUG = false;
    
        public TreeDemo() {
            super(new GridLayout(1,0));
    
            //Create the nodes.
            DefaultMutableTreeNode top = new DefaultMutableTreeNode("The Java Series");
            createNodes(top);  // call method to create nodes under root node
    
            //Create a tree that allows one selection at a time.
            tree = new JTree(top);
            tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
    
            //Listen for when the selection changes.
            tree.addTreeSelectionListener(this);
    
            //Create the scroll pane and add the tree to it. 
            JScrollPane treeView = new JScrollPane(tree);
    
            //Create the HTML viewing pane.
            htmlPane = new JEditorPane();
            htmlPane.setEditable(false);
            initHelp();
            JScrollPane htmlView = new JScrollPane(htmlPane);
    
            //Add the scroll panes to a split pane.
            JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
            splitPane.setTopComponent(treeView);
            splitPane.setBottomComponent(htmlView);
    
            Dimension minimumSize = new Dimension(100, 50);
            htmlView.setMinimumSize(minimumSize);
            treeView.setMinimumSize(minimumSize);
            splitPane.setDividerLocation(100); //XXX: ignored in some releases
                                               //of Swing. bug 4101306
            //workaround for bug 4101306:
            //treeView.setPreferredSize(new Dimension(100, 100)); 
    
            splitPane.setPreferredSize(new Dimension(500, 300));
    
            //Add the split pane to this panel.
            add(splitPane);
        }
    
    




    User Object: the argument to the DefaultMutableTreeNode constructor



        private class BookInfo {
            public String bookName;
            public URL bookURL;
    
            public BookInfo(String book, String filename) {
                bookName = book;
                bookURL = TreeDemo.class.getResource(filename);
                if (bookURL == null) {
                    System.err.println("Couldn't find file: "
                                       + filename);
                }
            }
    
            public String toString() {
                return bookName;
            }
        }
    
    

    Note: getResource is a method of java.lang.class, a subclass of java.lang.object.
    From the API:
    
    public URL getResource(String name)
     
    Finds a resource with a given name. This method returns null if no resource with this name is found. The rules for searching resources associated with a given class are implemented by the * defining class loader of the class. 
    
    This method delegates the call to its class loader, after making these changes to the resource name: if the resource name starts with "/", it is unchanged; otherwise, the package name is prepended to the resource name after converting "." to "/". If this object was loaded by the bootstrap loader, the call is delegated to ClassLoader.getSystemResource.
    
    Parameters:
    name - name of the desired resource
    Returns:
    a java.net.URL object.
    Since: 
    JDK1.1
    See Also: 
    ClassLoader
    




    TreeSelectionListener




        /** Required by TreeSelectionListener interface. */
        public void valueChanged(TreeSelectionEvent e) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)
                               tree.getLastSelectedPathComponent();  // this method belongs to class JTree
    
            if (node == null) return;
    
            Object nodeInfo = node.getUserObject();
            if (node.isLeaf()) {
                BookInfo book = (BookInfo)nodeInfo;
                displayURL(book.bookURL);
                if (DEBUG) {
                    System.out.print(book.bookURL + ":  \n    ");
                }
            } else {
                displayURL(helpURL); 
            }
            if (DEBUG) {
                System.out.println(nodeInfo.toString());
            }
        }
    
        private void displayURL(URL url) {
            try {
                if (url != null) {
                    htmlPane.setPage(url);  //a JEditorPane can diplay text/plain, text/html, text/rtf MIME types
                } else { //null url
    		htmlPane.setText("File Not Found");
                    if (DEBUG) {
                        System.out.println("Attempted to display a null URL.");
                    }
                }
            } catch (IOException e) {
                System.err.println("Attempted to read a bad URL: " + url);
            }
        }
    


    where setPage() method belongs to the JEditorPane class. From the API:
    public void setPage(URL page)
                 throws IOException
     
    Sets the current URL being displayed. The content type of the pane is set, and if the editor kit for the pane is non-null, then a new default document is created and the URL is read into it. 
    


    Creating the Nodes


    This method is passed the root node, an instance of DefaultMutableTreeNode

    
        private void createNodes(DefaultMutableTreeNode top) {
            DefaultMutableTreeNode category = null;
            DefaultMutableTreeNode book = null;
    
            category = new DefaultMutableTreeNode("Books for Java Programmers");
            top.add(category);
    
            //original Tutorial
            book = new DefaultMutableTreeNode(new BookInfo
                ("The Java Tutorial: A Short Course on the Basics",
                "tutorial.html"));
            category.add(book);
    
            //Tutorial Continued
            book = new DefaultMutableTreeNode(new BookInfo
                ("The Java Tutorial Continued: The Rest of the JDK",
                "tutorialcont.html"));
            category.add(book);
    
            //JFC Swing Tutorial
            book = new DefaultMutableTreeNode(new BookInfo
                ("The JFC Swing Tutorial: A Guide to Constructing GUIs",
                "swingtutorial.html"));
            category.add(book);
    
            //Bloch
            book = new DefaultMutableTreeNode(new BookInfo
                ("Effective Java Programming Language Guide",
    	     "bloch.html"));
            category.add(book);
    
            //Arnold/Gosling
            book = new DefaultMutableTreeNode(new BookInfo
                ("The Java Programming Language", "arnold.html"));
            category.add(book);
    
            //Chan
            book = new DefaultMutableTreeNode(new BookInfo
                ("The Java Developers Almanac",
                 "chan.html"));
            category.add(book);
    
            category = new DefaultMutableTreeNode("Books for Java Implementers");
            top.add(category);
    
            //VM
            book = new DefaultMutableTreeNode(new BookInfo
                ("The Java Virtual Machine Specification",
                 "vm.html"));
            category.add(book);
    
            //Language Spec
            book = new DefaultMutableTreeNode(new BookInfo
                ("The Java Language Specification",
                 "jls.html"));
            category.add(book);
        }
            
    




    Changing the Icon in a JTree




    
    public class TreeIconDemo extends JPanel implements TreeSelectionListener {
        private JEditorPane htmlPane;
        private JTree tree;
        private URL helpURL;
        private static boolean DEBUG = false;
    
        public TreeIconDemo() {
            super(new GridLayout(1,0));
    
            //Create the nodes.
            DefaultMutableTreeNode top =
                new DefaultMutableTreeNode("The Java Series");
            createNodes(top);
    
            //Create a tree that allows one selection at a time.
            tree = new JTree(top);
            tree.getSelectionModel().setSelectionMode
                    (TreeSelectionModel.SINGLE_TREE_SELECTION);
    
            //Set the icon for leaf nodes.
            ImageIcon leafIcon = createImageIcon("images/dukeWaveRed.gif");
            if (leafIcon != null) {
                DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
                renderer.setLeafIcon(leafIcon);
                tree.setCellRenderer(renderer);
            } else {
                System.err.println("Leaf icon missing; using default.");
            }
    
    // The rest of the code is the same as TreeDemo, except:
    
       /** Returns an ImageIcon, or null if the path was invalid. */
        protected static ImageIcon createImageIcon(String path) {
            java.net.URL imgURL = TreeIconDemo2.class.getResource(path);
            if (imgURL != null) {
                return new ImageIcon(imgURL);
            } else {
                System.err.println("Couldn't find file: " + path);
                return null;
            }
        }
    
    
    




    Varying Node Icon




    
    public class TreeIconDemo2 extends JPanel 
                               implements TreeSelectionListener {
        private JEditorPane htmlPane;
        private JTree tree;
        private URL helpURL;
        private static boolean DEBUG = false;
    
        public TreeIconDemo2() {
            super(new GridLayout(1,0));
    
            //Create the nodes.
            DefaultMutableTreeNode top =
                new DefaultMutableTreeNode("The Java Series");
            createNodes(top);
    
            //Create a tree that allows one selection at a time.
            tree = new JTree(top);
            tree.getSelectionModel().setSelectionMode
                    (TreeSelectionModel.SINGLE_TREE_SELECTION);
    
            //Enable tool tips. This lets us call setToolTipText() below.
            ToolTipManager.sharedInstance().registerComponent(tree);
    
            //Set the icon for leaf nodes.
            ImageIcon tutorialIcon = createImageIcon("images/middle.gif");
            if (tutorialIcon != null) {
                tree.setCellRenderer(new MyRenderer(tutorialIcon));
            } else {
                System.err.println("Tutorial icon missing; using default.");
            }
    
    
    etc., as in TreeDemo.
    Re: ToolTipManager, From the API:
    
    public class ToolTipManager
    extends MouseAdapter
    implements MouseMotionListener
     
    


    Finally:
    
        private class MyRenderer extends DefaultTreeCellRenderer {
            Icon tutorialIcon;
    
            public MyRenderer(Icon icon) {
                tutorialIcon = icon;
            }
    	// override this method from DefaultTreeCellRenderer:
            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);
                if (leaf && isTutorialBook(value)) {
                    setIcon(tutorialIcon);
                    setToolTipText("This book is in the Tutorial series.");
                } else {
                    setToolTipText(null); //no tool tip
                }
    
                return this;
            }
    
            protected boolean isTutorialBook(Object value) {
                DefaultMutableTreeNode node =
                        (DefaultMutableTreeNode)value;
                BookInfo nodeInfo = 
                        (BookInfo)(node.getUserObject());
                String title = nodeInfo.bookName;
                if (title.indexOf("Tutorial") >= 0) {
                    return true;
                } 
    
                return false;
            }