Java tutorial
/* This program is a part of the companion code for Core Java 8th ed. (http://horstmann.com/corejava) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ import java.awt.BorderLayout; import java.awt.Component; import java.awt.EventQueue; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Enumeration; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; /** * This program demonstrates cell rendering and listening to tree selection events. * @version 1.03 2007-08-01 * @author Cay Horstmann */ public class ClassTree { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame frame = new ClassTreeFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } } /** * This frame displays the class tree, a text field and add button to add more classes into the * tree. */ class ClassTreeFrame extends JFrame { public ClassTreeFrame() { setTitle("ClassTree"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); // the root of the class tree is Object root = new DefaultMutableTreeNode(java.lang.Object.class); model = new DefaultTreeModel(root); tree = new JTree(model); // add this class to populate the tree with some data addClass(getClass()); // set up node icons ClassNameTreeCellRenderer renderer = new ClassNameTreeCellRenderer(); renderer.setClosedIcon(new ImageIcon("red-ball.gif")); renderer.setOpenIcon(new ImageIcon("yellow-ball.gif")); renderer.setLeafIcon(new ImageIcon("blue-ball.gif")); tree.setCellRenderer(renderer); // set up selection mode tree.addTreeSelectionListener(new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent event) { // the user selected a different node--update description TreePath path = tree.getSelectionPath(); if (path == null) return; DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent(); Class<?> c = (Class<?>) selectedNode.getUserObject(); String description = getFieldDescription(c); textArea.setText(description); } }); int mode = TreeSelectionModel.SINGLE_TREE_SELECTION; tree.getSelectionModel().setSelectionMode(mode); // this text area holds the class description textArea = new JTextArea(); // add tree and text area JPanel panel = new JPanel(); panel.setLayout(new GridLayout(1, 2)); panel.add(new JScrollPane(tree)); panel.add(new JScrollPane(textArea)); add(panel, BorderLayout.CENTER); addTextField(); } /** * Add the text field and "Add" button to add a new class. */ public void addTextField() { JPanel panel = new JPanel(); ActionListener addListener = new ActionListener() { public void actionPerformed(ActionEvent event) { // add the class whose name is in the text field try { String text = textField.getText(); addClass(Class.forName(text)); // clear text field to indicate success textField.setText(""); } catch (ClassNotFoundException e) { JOptionPane.showMessageDialog(null, "Class not found"); } } }; // new class names are typed into this text field textField = new JTextField(20); textField.addActionListener(addListener); panel.add(textField); JButton addButton = new JButton("Add"); addButton.addActionListener(addListener); panel.add(addButton); add(panel, BorderLayout.SOUTH); } /** * Finds an object in the tree. * @param obj the object to find * @return the node containing the object or null if the object is not present in the tree */ @SuppressWarnings("unchecked") public DefaultMutableTreeNode findUserObject(Object obj) { // find the node containing a user object Enumeration<TreeNode> e = (Enumeration<TreeNode>) root.breadthFirstEnumeration(); while (e.hasMoreElements()) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.nextElement(); if (node.getUserObject().equals(obj)) return node; } return null; } /** * Adds a new class and any parent classes that aren't yet part of the tree * @param c the class to add * @return the newly added node. */ public DefaultMutableTreeNode addClass(Class<?> c) { // add a new class to the tree // skip non-class types if (c.isInterface() || c.isPrimitive()) return null; // if the class is already in the tree, return its node DefaultMutableTreeNode node = findUserObject(c); if (node != null) return node; // class isn't present--first add class parent recursively Class<?> s = c.getSuperclass(); DefaultMutableTreeNode parent; if (s == null) parent = root; else parent = addClass(s); // add the class as a child to the parent DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(c); model.insertNodeInto(newNode, parent, parent.getChildCount()); // make node visible TreePath path = new TreePath(model.getPathToRoot(newNode)); tree.makeVisible(path); return newNode; } /** * Returns a description of the fields of a class. * @param the class to be described * @return a string containing all field types and names */ public static String getFieldDescription(Class<?> c) { // use reflection to find types and names of fields StringBuilder r = new StringBuilder(); Field[] fields = c.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field f = fields[i]; if ((f.getModifiers() & Modifier.STATIC) != 0) r.append("static "); r.append(f.getType().getName()); r.append(" "); r.append(f.getName()); r.append("\n"); } return r.toString(); } private DefaultMutableTreeNode root; private DefaultTreeModel model; private JTree tree; private JTextField textField; private JTextArea textArea; private static final int DEFAULT_WIDTH = 400; private static final int DEFAULT_HEIGHT = 300; } /** * This class renders a class name either in plain or italic. Abstract classes are italic. */ class ClassNameTreeCellRenderer extends DefaultTreeCellRenderer { public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus); // get the user object DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; Class<?> c = (Class<?>) node.getUserObject(); // the first time, derive italic font from plain font if (plainFont == null) { plainFont = getFont(); // the tree cell renderer is sometimes called with a label that has a null font if (plainFont != null) italicFont = plainFont.deriveFont(Font.ITALIC); } // set font to italic if the class is abstract, plain otherwise if ((c.getModifiers() & Modifier.ABSTRACT) == 0) setFont(plainFont); else setFont(italicFont); return this; } private Font plainFont = null; private Font italicFont = null; }