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;
}
运行效果: