package tree; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.util.Hashtable; import java.util.Vector; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.event.TreeSelectionEvent; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; // // This file is to reproduce tree node bugs for JRE1.6 // public class treetest extends JFrame { private TreeBugDemo tree; public treetest() { tree = new TreeBugDemo(); this.setSize(700, 700); this.Init(); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } private void Init() { Container cp = this.getContentPane(); cp.setLayout(null); JScrollPane jsp = new JScrollPane(tree); jsp.setBounds(100, 20, 500, 500); jsp.setPreferredSize(new Dimension(300, 500)); cp.add(jsp); Thread ta = new Thread(tree, "Thread-Tree"); ta.start(); } public static void main(String[] args) { treetest tb = new treetest(); } } class MyTreeModel extends DefaultTreeModel { public MyTreeModel(TreeNode root) { super(root); } public synchronized void nodeChanged(TreeNode node) { System.out.println("Node changed:" + node); try { super.nodeChanged(node); } catch (Exception e) { System.out.println("Exception squelched in nodeChanged()\n" + "\t" + e.toString()); } notify(); } } class TreeBugDemo extends JTree implements Runnable { private DefaultMutableTreeNode root; private DefaultTreeModel model; private DefaultMutableTreeNode selectedNode = null; private DefaultMutableTreeNode[] chgNode = new DefaultMutableTreeNode[21]; public TreeBugDemo() { super(); this.setRootVisible(true); NodeDt rootData = new NodeDt("ROOT"); root = new DefaultMutableTreeNode(rootData); model = new MyTreeModel(root); model.setRoot(root); this.setModel(model); this.setCellRenderer(new CellRender()); this.testLoaddata(); } private NodeDt convNode(int i) { String nodeName = ""; switch (i) { case 0: nodeName = "WINE"; break; case 1: nodeName = "CIGARETTE"; break; case 2: nodeName = "SUGAR"; break; default: nodeName = "Default"; break; } return new NodeDt(nodeName); } private void testLoaddata() { Hashtable table = new Hashtable(); for (int i = 0; i < 3; i++) { // nodes under root NodeDt nd = convNode(i); Vector vec = new Vector(); // Generate children for (int j = 0; j < 21; j++) { int min = j; int max = j + 3; int value = j; vec.addElement(new NodeDt(min, max, value, "wine-" + (j + 1))); } table.put(nd, vec); } this.LoadData(table); } public void LoadData(Hashtable nodes) { Vector child; Vector parent = new Vector(); java.util.Enumeration en = nodes.keys(); // Nodes under root while (en.hasMoreElements()) { parent.addElement(en.nextElement()); } for (int i = 0; i < parent.size(); i++) { child = (Vector) nodes.get(parent.elementAt(i)); // all childeren // under this parent DefaultMutableTreeNode parentNode = this .addParentNode((NodeDt) parent.elementAt(i)); System.out.println("Node:" + parent.elementAt(i) + " is added to root."); for (int j = 0; j < child.size(); j++) { if (parentNode.getUserObject().toString().equals("WINE")) { chgNode[j] = this.addChildNode(parentNode, (NodeDt) child .elementAt(j)); } else { this .addChildNode(parentNode, (NodeDt) child .elementAt(j)); } } } } public DefaultMutableTreeNode addParentNode(NodeDt NodeDt) { DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(NodeDt); ((DefaultMutableTreeNode) model.getRoot()).add(newNode); return newNode; } public DefaultMutableTreeNode addParentNode( DefaultMutableTreeNode parentNode, NodeDt NodeDt) { DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(NodeDt); parentNode.add(newNode); return newNode; } public DefaultMutableTreeNode addChildNode(DefaultMutableTreeNode node, NodeDt NodeDt) { DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(NodeDt); node.add(childNode); return childNode; } public void reBuild() { root.removeAllChildren(); this.testLoaddata(); } public void valueChanged(TreeSelectionEvent evt) { TreePath path = evt.getNewLeadSelectionPath(); TreePath oldPath = evt.getOldLeadSelectionPath(); if (path == null) { // this will only happened when collpase a tree node, or change // selection from a tree node to a table cell if (selectedNode != null) { TreeNode paths[] = selectedNode.getPath(); for (int i = 0; i < paths.length; ++i) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) paths[i]; } repaint(); System.out.println("valueChanged:Tree repainted!"); } selectedNode = null; return; } selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent(); DefaultMutableTreeNode oldSNode = null; if (oldPath != null) { oldSNode = (DefaultMutableTreeNode) oldPath.getLastPathComponent(); } // set highlighted path of selected node this.repaint(); System.out.println("valueChanged:Tree repainted!"); } public void run() { // TODO Auto-generated method stub int i = 1; while (true) { System.out.println("Thread is running ..."); ((NodeDt) chgNode[0].getUserObject()).setValue(i++); model.nodeChanged(chgNode[0]); for (int j = 1; j < chgNode.length; j++) { System.out.println("Node changed:" + chgNode[j]); model.nodeChanged(chgNode[j]); } try { Thread.sleep(8000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } class NodeDt { private String name; private int min; private int max; private int value; private boolean isLeaf = true; private String card = null; public NodeDt(String name) { this.name = name; this.isLeaf = false; } public NodeDt(int min, int max, int value, String card) { this.min = min; this.max = max; this.value = value; this.isLeaf = true; this.card = card; } public boolean isLeaf() { return this.isLeaf; } public boolean isOverflow() { if (this.isLeaf == true) { if (value <= max && value >= min) { return true; } else { return false; } } else { return false; } } public String toString() { if (this.isLeaf()) { return card + "; value= " + value + "; min=" + min + "; max=" + max; } else { return this.name; } } public void setUrl(String newUrl) { this.card = newUrl; } public String getUrl() { return this.card; } public void setValue(int val) { this.value = val; } } class CellRender extends JLabel implements TreeCellRenderer { protected Color selectedBackground; protected Color selectedForeground; protected Color noselectedBackground; protected Color noselectedForeground; protected Color overflowBackground = Color.yellow; protected Color overflowForeground = Color.red; protected Color overflowSelectedBG = Color.green; protected Color overflowSelectedFG = Color.black; public CellRender() { super(); this.selectedBackground = Color.blue; this.selectedForeground = Color.green; this.noselectedBackground = Color.white; this.noselectedForeground = Color.blue; this.setForeground(this.noselectedForeground); this.setBackground(this.noselectedBackground); } public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; System.out.println("Thread:" + Thread.currentThread().getId() + "; getTreeCellRendererComponent:Update node:" + node + "; row=" + row); NodeDt nd; if (leaf) { nd = (NodeDt) node.getUserObject(); } else { nd = checkChild(node); } if (!nd.isOverflow()) { if (selected) { this.setForeground(this.selectedForeground); this.setBackground(this.selectedBackground); } else { this.setBackground(this.noselectedBackground); this.setForeground(this.noselectedForeground); } } else { if (selected) { this.setBackground(this.overflowSelectedBG); this.setForeground(this.overflowSelectedFG); } else { this.setBackground(this.overflowBackground); this.setForeground(this.overflowForeground); } } this.setText(value.toString()); return this; } private NodeDt checkChild(DefaultMutableTreeNode childNode) { NodeDt child = null; int count = childNode.getChildCount(); for (int i = 0; i < count; i++) { DefaultMutableTreeNode childNodes = (DefaultMutableTreeNode) childNode .getChildAt(i); if (childNodes.isLeaf()) { child = (NodeDt) childNodes.getUserObject(); if (child.isOverflow()) { break; } } else { child = checkChild(childNodes); } } return child; } }