Java核心技术II-第6章-对象树-源代码
Java核心技术II-第6章-对象树-源代码,在博文的最后有运行效果图。
package javaee.vii.ch06; import java.awt.EventQueue; import javax.swing.JFrame; /** * This program demonstrates cell rendering and listening to tree selection * events. * * @author lcwell */ 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); } }); } }
package javaee.vii.ch06; import java.awt.Component; import java.awt.Font; import java.lang.reflect.Modifier; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; /** * This class renders a class name either in plain or italic. Abstract classes * are italic. * * @author lcwell */ public class ClassNameTreeCellRenderer extends DefaultTreeCellRenderer { @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { Component comp = super.getTreeCellRendererComponent(tree, value, leaf, expanded, leaf, row, hasFocus); // get the user object DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; Class<?> c = (Class<?>) node.getUserObject(); // the first time, derive itablic 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 != null && (c.getModifiers() & Modifier.ABSTRACT) == 0) { setFont(plainFont); } else { comp.setFont(italicFont); } return comp; } private Font plainFont = null; private Font italicFont = null; }
package javaee.vii.ch06; import java.awt.BorderLayout; 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.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; /** * This frame displays the class tree, a text field and add button to * add more classes into the tree. * @author lcwell */ public 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("src/images/1.jpg")); renderer.setOpenIcon(new ImageIcon("src/images/2.jpg")); renderer.setLeafIcon(new ImageIcon("src/images/3.jpg")); tree.setCellRenderer(renderer); // set up selection mode tree.addTreeSelectionListener(new TreeSelectionListener(){ public void valueChanged(TreeSelectionEvent event) { // the user selected a diffent 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 objects is not persent 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 != null & obj.equals(node.getUserObject())) return node; } return null; } /** * Adds a new 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; } /** * Return a description to find types and names of fields. * @param c the classt o be described * @return a string contraining all field types and names */ public static String getFieldDescription(Class<?> c) { // use reflection to find types and names of fileds StringBuilder r = new StringBuilder(); Field[] fields = c.getDeclaredFields(); for (Field f : fields) { 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; }
运行效果: