Mega Code Archive

 
Categories / Java / Swing JFC
 

This program demonstrates cell rendering and listening to tree selection events

/*    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; }