ComponentTree.java Source code

Java tutorial

Introduction

Here is the source code for ComponentTree.java

Source

/*
 * Copyright (c) 2000 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 2nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book (recommended),
 * visit http://www.davidflanagan.com/javaexamples2.
 */

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

/**
 * This class is a JTree subclass that displays the tree of AWT or Swing
 * component that make up a GUI.
 */
public class ComponentTree extends JTree {
    /**
     * All this constructor method has to do is set the TreeModel and
     * TreeCellRenderer objects for the tree. It is these classes (defined
     * below) that do all the real work.
     */
    public ComponentTree(Component c) {
        super(new ComponentTreeModel(c));
        setCellRenderer(new ComponentCellRenderer(getCellRenderer()));
    }

    /**
     * The TreeModel class puts hierarchical data in a form that the JTree can
     * display. This implementation interprets the containment hierarchy of a
     * Component for display by the ComponentTree class. Note that any kind of
     * Object can be a node in the tree, as long as the TreeModel knows how to
     * handle it.
     */
    static class ComponentTreeModel implements TreeModel {
        Component root; // The root object of the tree

        // Constructor: just remember the root object
        public ComponentTreeModel(Component root) {
            this.root = root;
        }

        // Return the root of the tree
        public Object getRoot() {
            return root;
        }

        // Is this node a leaf? (Leaf nodes are displayed differently by JTree)
        // Any node that isn't a container is a leaf, since they cannot have
        // children. We also define containers with no children as leaves.
        public boolean isLeaf(Object node) {
            if (!(node instanceof Container))
                return true;
            Container c = (Container) node;
            return c.getComponentCount() == 0;
        }

        // How many children does this node have?
        public int getChildCount(Object node) {
            if (node instanceof Container) {
                Container c = (Container) node;
                return c.getComponentCount();
            }
            return 0;
        }

        // Return the specified child of a parent node.
        public Object getChild(Object parent, int index) {
            if (parent instanceof Container) {
                Container c = (Container) parent;
                return c.getComponent(index);
            }
            return null;
        }

        // Return the index of the child node in the parent node
        public int getIndexOfChild(Object parent, Object child) {
            if (!(parent instanceof Container))
                return -1;
            Container c = (Container) parent;
            Component[] children = c.getComponents();
            if (children == null)
                return -1;
            for (int i = 0; i < children.length; i++) {
                if (children[i] == child)
                    return i;
            }
            return -1;
        }

        // This method is only required for editable trees, so it is not
        // implemented here.
        public void valueForPathChanged(TreePath path, Object newvalue) {
        }

        // This TreeModel never fires any events (since it is not editable)
        // so event listener registration methods are left unimplemented
        public void addTreeModelListener(TreeModelListener l) {
        }

        public void removeTreeModelListener(TreeModelListener l) {
        }
    }

    /**
     * A TreeCellRenderer displays each node of a tree. The default renderer
     * displays arbitrary Object nodes by calling their toString() method. The
     * Component.toString() method returns long strings with extraneous
     * information. Therefore, we use this "wrapper" implementation of
     * TreeCellRenderer to convert nodes from Component objects to useful String
     * values before passing those String values on to the default renderer.
     */
    static class ComponentCellRenderer implements TreeCellRenderer {
        TreeCellRenderer renderer; // The renderer we are a wrapper for

        // Constructor: just remember the renderer
        public ComponentCellRenderer(TreeCellRenderer renderer) {
            this.renderer = renderer;
        }

        // This is the only TreeCellRenderer method.
        // Compute the string to display, and pass it to the wrapped renderer
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
                boolean leaf, int row, boolean hasFocus) {
            String newvalue = value.getClass().getName(); // Component type
            String name = ((Component) value).getName(); // Component name
            if (name != null)
                newvalue += " (" + name + ")"; // unless null
            // Use the wrapped renderer object to do the real work
            return renderer.getTreeCellRendererComponent(tree, newvalue, selected, expanded, leaf, row, hasFocus);
        }
    }

    /**
     * This main() method demonstrates the use of the ComponentTree class: it
     * puts a ComponentTree component in a Frame, and uses the ComponentTree to
     * display its own GUI hierarchy. It also adds a TreeSelectionListener to
     * display additional information about each component as it is selected
     */
    public static void main(String[] args) {
        // Create a frame for the demo, and handle window close requests
        JFrame frame = new JFrame("ComponentTree Demo");
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        // Create a scroll pane and a "message line" and add them to the
        // center and bottom of the frame.
        JScrollPane scrollpane = new JScrollPane();
        final JLabel msgline = new JLabel(" ");
        frame.getContentPane().add(scrollpane, BorderLayout.CENTER);
        frame.getContentPane().add(msgline, BorderLayout.SOUTH);

        // Now create the ComponentTree object, specifying the frame as the
        // component whose tree is to be displayed. Also set the tree's font.
        JTree tree = new ComponentTree(frame);
        tree.setFont(new Font("SansSerif", Font.BOLD, 12));

        // Only allow a single item in the tree to be selected at once
        tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

        // Add an event listener for notifications when
        // the tree selection state changes.
        tree.addTreeSelectionListener(new TreeSelectionListener() {
            public void valueChanged(TreeSelectionEvent e) {
                // Tree selections are referred to by "path"
                // We only care about the last node in the path
                TreePath path = e.getPath();
                Component c = (Component) path.getLastPathComponent();
                // Now we know what component was selected, so
                // display some information about it in the message line
                if (c.isShowing()) {
                    Point p = c.getLocationOnScreen();
                    msgline.setText("x: " + p.x + "  y: " + p.y + "  width: " + c.getWidth() + "  height: "
                            + c.getHeight());
                } else {
                    msgline.setText("component is not showing");
                }
            }
        });

        // Now that we've set up the tree, add it to the scrollpane
        scrollpane.setViewportView(tree);

        // Finally, set the size of the main window, and pop it up.
        frame.setSize(600, 400);
        frame.setVisible(true);
    }
}