10-1:使用JTree组件: java.lang.Object --java.awt.Component --java.awt.Container --javax.swing.JComponent --javax.swing.JTreeJTree构造函数:JTree():建立一棵系统默认的树。JTree(Hashtable value):利用Hashtable建立树,不显示root node(根节点).JTree(Object[] value):利用Object Array建立树,不显示root node.JTree(TreeModel newModel):利用TreeModel建立树。JTree(TreeNode root):利用TreeNode建立树。JTree(TreeNode root,boolean asksAllowsChildren):利用TreeNode建立树,并决定是否允许子节点的存在.JTree(Vector value):利用Vector建立树,不显示root node.
范例:InitalTree.java
import javax.swing.*;import java.awt.*;import java.awt.event.*;
public class InitalTree{ public InitalTree(){ JFrame f=new JFrame("TreeDemo"); Container contentPane=f.getContentPane(); JTree tree=new JTree(); JScrollPane scrollPane=new JScrollPane(); scrollPane.setViewportView(tree); contentPane.add(scrollPane); f.pack(); f.setVisible(true); f.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); } public static void main(String[] args){ new InitalTree(); }}
10-2:以Hashtable构造JTree: 上面的例子对我们并没有裨的帮助,因为各个节点的数据均是java的默认值,而非我们自己设置的。因此我们需利用其他JTree构造函数来输入我们想要的节点数据。以下范例我们以Hashtable当作JTree的数据输入:范例:TreeDemo1.java
import javax.swing.*;import java.awt.*;import java.awt.event.*;import java.util.*;
public class TreeDemo1{ public TreeDemo1(){ JFrame f=new JFrame("TreeDemo1"); Container contentPane=f.getContentPane(); String[] s1={"公司文件","个人信件","私人文件"}; String[] s2={"本机磁盘(C:)","本机磁盘(D:)","本机磁盘(E:)"}; String[] s3={"奇摩站","职棒消息","网络书店"}; Hashtable hashtable1=new Hashtable(); Hashtable hashtable2=new Hashtable(); hashtable1.put("我的公文包",s1); hashtable1.put("我的电脑",s2); hashtable1.put("收藏夹",hashtable2); hashtable2.put("网站列表",s3); Font font = new Font("Dialog", Font.PLAIN, 12); Enumeration keys = UIManager.getLookAndFeelDefaults().keys(); /**定义widnows界面**/ while (keys.hasMoreElements()) { Object key = keys.nextElement(); if (UIManager.get(key) instanceof Font) { UIManager.put(key, font); } } try{ UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); }catch(Exception el){ System.exit(0); } /**定义widnows界面**/ JTree tree=new JTree(hashtable1); JScrollPane scrollPane=new JScrollPane(); scrollPane.setViewportView(tree); contentPane.add(scrollPane); f.pack(); f.setVisible(true); f.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); } public static void main(String[] args){ new TreeDemo1(); }}
纯XP界面的设置:
10-3:以TreeNode构造JTree: JTree上的每一个节点就代表一个TreeNode对象,TreeNode本身是一个Interface,里面定义了7个有关节点的方法,例如判断是否为树叶节点、有几个子节点(getChildCount())、父节点为何(getparent())等等、这些方法的定义你可以在javax.swing.tree的package中找到,读者可自行查阅java api文件。在实际的应用上,一般我们不会直接实作此界面,而是采用java所提供的DefaultMutableTreeMode类,此类是实作MutableTreeNode界面而来,并提供了其他许多实用的方法。MutableTreeNode本身也是一个Interface,且继承了TreeNode界面此类主要是定义一些节点的处理方式,例如新增节点(insert())、删除节点(remove())、设置节点(setUserObject())等。整个关系如下图: TreeNode----extends--->MutableTreeNode---implements---DefaultMutableTreeNode
接下来我们来看如何利DefaultMutableTreeNode来建立JTree,我们先来看DefaultMutableTreeNode的构造函数:
DefaultMutableTreeNode构造函数:DefaultMutableTreeNode():建立空的DefaultMutableTreeNode对象。DefaultMutableTreeNode(Object userObject):建立DefaultMutableTreeNode对象,节点为userObject对象。DefaultMutableTreeNode(Object userObject,Boolean allowsChildren):建立DefaultMutableTreeNode对象,节点为userObject对 象并决定此节点是否允许具有子节点。 以下为利用DefaultMutableTreeNode建立JTree的范例:TreeDemo2.java 此程序"资源管理器"为此棵树的根节点.import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.tree.*;public class TreeDemo2{ public TreeDemo2(){ JFrame f=new JFrame("TreeDemo2"); Container contentPane=f.getContentPane(); DefaultMutableTreeNode root=new DefaultMutableTreeNode("资源管理器"); DefaultMutableTreeNode node1=new DefaultMutableTreeNode("我的公文包"); DefaultMutableTreeNode node2=new DefaultMutableTreeNode("我的电脑"); DefaultMutableTreeNode node3=new DefaultMutableTreeNode("收藏夹"); DefaultMutableTreeNode node4=new DefaultMutableTreeNode("Readme"); root.add(node1); root.add(node2); root.add(node3); root.add(node4); DefaultMutableTreeNode leafnode=new DefaultMutableTreeNode("公司文件"); node1.add(leafnode); leafnode=new DefaultMutableTreeNode("私人文件"); node1.add(leafnode); leafnode=new DefaultMutableTreeNode("个人信件"); leafnode=new DefaultMutableTreeNode("本机磁盘(C:)"); node2.add(leafnode); leafnode=new DefaultMutableTreeNode("本机磁盘(D:)"); node2.add(leafnode); leafnode=new DefaultMutableTreeNode("本机磁盘(E:)"); node2.add(leafnode); DefaultMutableTreeNode node31=new DefaultMutableTreeNode("网站列表"); node3.add(node31); leafnode=new DefaultMutableTreeNode("奇摩站"); node31.add(leafnode); leafnode=new DefaultMutableTreeNode("职棒消息"); node31.add(leafnode); leafnode=new DefaultMutableTreeNode("网络书店"); node31.add(leafnode); JTree tree=new JTree(root); JScrollPane scrollPane=new JScrollPane(); scrollPane.setViewportView(tree); contentPane.add(scrollPane); f.pack(); f.setVisible(true); f.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); } public static void main(String[] args){ new TreeDemo2(); } }
10-4:以TreeModel构造JTree. 除了以节点的观念(TreeNode)建立树之外,你可以用data model的模式建立树。树的data model称为TreeModel,用此模式的好处是可以触发相关的树事件,来处理树可能产生的一些变动。TreeModel是一个interface,里面定义了8种方法;如果你是一个喜欢自己动手做的人,或是你想显示的数据格式很复杂,你可以考虑直接实作TreeModel界面中所定义的方法来构造出JTree.TreeModel界面的方法如下所示:TreeModel方法:void addTreeModelListener(TreeModelListener l):增加一个TreeModelListener来监控TreeModelEvent事件。Object getChild(Object parent,int index):返回子节点。int getChildCount(Object parent):返回子节点数量.int getIndexOfChild(Object parent,Object child):返回子节点的索引值。Object getRoot():返回根节点。boolean isLeaf(Object node):判断是否为树叶节点。void removeTreeModelListener(TreeModelListener l):删除TreeModelListener。void valueForPathChanged(TreePath path,Object newValue):当用户改变Tree上的值时如何应对。
你可以实作出这8种方法,然后构造出自己想要的JTree,不过在大部份的情况下我们通常不会这样做,毕竟要实作出这8种方法不是件很轻松的事,而且java本身也提供了一个默认模式,叫做DefaultTreeModel,这个类已经实作了TreeModel界面,也另外提供许多实用的方法。利用这个默认模式,我们便能很方便的构造出JTree出来了。下面为DefaultTreeModel的构造函数与范例:DefaultTreeModel构造函数:DefaultTreeModel(TreeNode root):建立DefaultTreeModel对象,并定出根节点。DefaultTreeModel(TreeNode root,Boolean asksAllowsChildren):建立具有根节点的DefaultTreeModel对象,并决定此节点是否允 许具有子节点。
import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.tree.*;import com.incors.plaf.alloy.*;//组件的下载网http://www.incors.com/lookandfeel//*将alloy.jar放在c:/j2sdk1.4.0/jre/lib/ext/目录下.*/public class TreeDemo3{ public TreeDemo3() { JFrame f = new JFrame("TreeDemo"); Container contentPane = f.getContentPane(); DefaultMutableTreeNode root = new DefaultMutableTreeNode("资源管理器"); DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("我的公文包"); DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的电脑"); DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夹"); DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme"); DefaultTreeModel treeModel = new DefaultTreeModel(root);
/*DefaultTreeModel类所提供的insertNodeInto()方法加入节点到父节点的数量. *利用DefaultMutableTreeNode类所提供的getChildCount()方法取得目前子节点的数量. */ treeModel.insertNodeInto(node1, root, root.getChildCount()); treeModel.insertNodeInto(node2, root, root.getChildCount()); treeModel.insertNodeInto(node3, root, root.getChildCount()); treeModel.insertNodeInto(node4, root, root.getChildCount()); DefaultMutableTreeNode leafnode = new DefaultMutableTreeNode("公司文件");
//DefaultTreeModel类所提供的insertNodeInto()方法加入节点到父节点的数量. treeModel.insertNodeInto(leafnode, node1, node1.getChildCount()); leafnode = new DefaultMutableTreeNode("个人信件"); treeModel.insertNodeInto(leafnode, node1, node1.getChildCount()); leafnode = new DefaultMutableTreeNode("私人文件"); treeModel.insertNodeInto(leafnode, node1, node1.getChildCount()); leafnode = new DefaultMutableTreeNode("本机磁盘(C:)"); treeModel.insertNodeInto(leafnode, node2, node2.getChildCount()); leafnode = new DefaultMutableTreeNode("本机磁盘(D:)"); treeModel.insertNodeInto(leafnode, node2, node2.getChildCount()); leafnode = new DefaultMutableTreeNode("本机磁盘(E:)"); treeModel.insertNodeInto(leafnode, node2, node2.getChildCount()); DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("网站列表"); treeModel.insertNodeInto(node31, node3, node3.getChildCount()); leafnode = new DefaultMutableTreeNode("奇摩站"); treeModel.insertNodeInto(leafnode, node3, node3.getChildCount()); leafnode = new DefaultMutableTreeNode("职棒消息"); treeModel.insertNodeInto(leafnode, node3, node3.getChildCount()); leafnode = new DefaultMutableTreeNode("网络书店"); treeModel.insertNodeInto(leafnode, node3, node3.getChildCount()); try { LookAndFeel alloyLnF = new AlloyLookAndFeel(); UIManager.setLookAndFeel(alloyLnF); } catch (UnsupportedLookAndFeelException ex) { // You may handle the exception here } // this line needs to be implemented in order to make JWS work properly UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader()); //以TreeModel建立JTree。 JTree tree = new JTree(treeModel); /*改变JTree的外观**/ tree.putClientProperty("JTree.lineStyle","Horizontal"); /*改变JTree的外观**/ JScrollPane scrollPane = new JScrollPane(); scrollPane.setViewportView(tree); contentPane.add(scrollPane); f.pack(); f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });
}
public static void main(String args[]) { new TreeDemo3(); }}10-5:改变JTree的外观:你可以使用JComponent所提供的putClientProperty(Object key,Object value)方法来设置java默认的JTree外观,设置方式共有3种:1.tree.putClientProperty("JTree.lineStyle","None"):java默认值。2.tree.putClientProperty("JTree.lineStyle","Horizontal"):使JTree的文件夹间具有水平分隔线。3.tree.putClientProperty("JTree.lineStyle","Angled"):使JTree具有类似Windows文件管理器的直角连接线。 具体怎样做,可看上例.
10-6:更换JTree节点图案: JTree利用TreeCellRenderer界面来运行绘制节点的工作,同样的,你不需要直接支实作这个界面所定义的方法,因为java本身提供一个已经实作好的类来给我们使用,此类就是DefaultTreeCellRenderer,你可以在javax.swing.tree package中找到此类所提供的方法。下面为使用DefaultTreeCellRenderer更改节点图案的一个例子:
import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.tree.*;import com.incors.plaf.alloy.*;
public class TreeDemo4{ public TreeDemo4(){ JFrame f=new JFrame("TreeDemo"); Container contentPane=f.getContentPane(); DefaultMutableTreeNode root = new DefaultMutableTreeNode("资源管理器"); DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("我的公文包"); DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的电脑"); DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夹"); DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme"); DefaultTreeModel treeModel = new DefaultTreeModel(root); treeModel.insertNodeInto(node1, root, root.getChildCount()); treeModel.insertNodeInto(node2, root, root.getChildCount()); treeModel.insertNodeInto(node3, root, root.getChildCount()); treeModel.insertNodeInto(node4, root, root.getChildCount()); DefaultMutableTreeNode leafnode = new DefaultMutableTreeNode("公司文件"); treeModel.insertNodeInto(leafnode, node1, node1.getChildCount()); leafnode = new DefaultMutableTreeNode("个人信件"); treeModel.insertNodeInto(leafnode, node1, node1.getChildCount()); leafnode = new DefaultMutableTreeNode("私人文件"); treeModel.insertNodeInto(leafnode, node1, node1.getChildCount()); leafnode = new DefaultMutableTreeNode("本机磁盘(C:)"); treeModel.insertNodeInto(leafnode, node2, node2.getChildCount()); leafnode = new DefaultMutableTreeNode("本机磁盘(D:)"); treeModel.insertNodeInto(leafnode, node2, node2.getChildCount()); leafnode = new DefaultMutableTreeNode("本机磁盘(E:)"); treeModel.insertNodeInto(leafnode, node2, node2.getChildCount()); DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("网站列表"); treeModel.insertNodeInto(node31, node3, node3.getChildCount()); leafnode = new DefaultMutableTreeNode("奇摩站"); treeModel.insertNodeInto(leafnode, node3, node3.getChildCount()); leafnode = new DefaultMutableTreeNode("职棒消息"); treeModel.insertNodeInto(leafnode, node3, node3.getChildCount()); leafnode = new DefaultMutableTreeNode("网络书店"); treeModel.insertNodeInto(leafnode, node3, node3.getChildCount()); try { LookAndFeel alloyLnF = new AlloyLookAndFeel(); UIManager.setLookAndFeel(alloyLnF); } catch (UnsupportedLookAndFeelException ex) { // You may handle the exception here } // this line needs to be implemented in order to make JWS work properly UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader());
JTree tree = new JTree(treeModel); tree.setRowHeight(20); DefaultTreeCellRenderer cellRenderer=(DefaultTreeCellRenderer)tree.getCellRenderer(); cellRenderer.setLeafIcon(new ImageIcon("..//icons//leaf.gif")); cellRenderer.setOpenIcon(new ImageIcon("..//icons//open.gif")); cellRenderer.setClosedIcon(new ImageIcon("..//icons//close.gif")); cellRenderer.setFont(new Font("宋体",Font.PLAIN,12));//设置字体. cellRenderer.setBackgroundNonSelectionColor(Color.white); cellRenderer.setBackgroundSelectionColor(Color.yellow); cellRenderer.setBorderSelectionColor(Color.red); /*设置选时或不选时,文字的变化颜色 */ cellRenderer.setTextNonSelectionColor(Color.black); cellRenderer.setTextSelectionColor(Color.blue); JScrollPane scrollPane=new JScrollPane(); scrollPane.setViewportView(tree); contentPane.add(scrollPane); f.pack(); f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });
}
public static void main(String args[]) { new TreeDemo4(); }}Window Xp界面:
import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.tree.*;import com.incors.plaf.alloy.*;public class TreeDemo3{ public TreeDemo3() { //设置成Alloy界面样式 try { AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true"); LookAndFeel alloyLnF = new AlloyLookAndFeel(); JFrame.setDefaultLookAndFeelDecorated(true); UIManager.setLookAndFeel(alloyLnF); } catch (UnsupportedLookAndFeelException ex) { // You may handle the exception here } // this line needs to be implemented in order to make JWS work properly UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader()); //JDialog.setDefaultLookAndFeelDecorated(true); JFrame f = new JFrame("firstTree"); Container contentPane = f.getContentPane(); // if (contentPane instanceof JComponent) { // ((JComponent) contentPane).setMinimumSize(new Dimension(100, 100)); //} // Container contentPane = f.getContentPane(); DefaultMutableTreeNode root = new DefaultMutableTreeNode("资源管理器"); DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("我的公文包"); DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的电脑"); DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夹"); DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme"); DefaultTreeModel treeModel = new DefaultTreeModel(root); treeModel.insertNodeInto(node1, root, root.getChildCount()); treeModel.insertNodeInto(node2, root, root.getChildCount()); treeModel.insertNodeInto(node3, root, root.getChildCount()); treeModel.insertNodeInto(node4, root, root.getChildCount()); DefaultMutableTreeNode leafnode = new DefaultMutableTreeNode("公司文件"); treeModel.insertNodeInto(leafnode, node1, node1.getChildCount()); leafnode = new DefaultMutableTreeNode("个人信件"); treeModel.insertNodeInto(leafnode, node1, node1.getChildCount()); leafnode = new DefaultMutableTreeNode("私人文件"); treeModel.insertNodeInto(leafnode, node1, node1.getChildCount()); leafnode = new DefaultMutableTreeNode("本机磁盘(C:)"); treeModel.insertNodeInto(leafnode, node2, node2.getChildCount()); leafnode = new DefaultMutableTreeNode("本机磁盘(D:)"); treeModel.insertNodeInto(leafnode, node2, node2.getChildCount()); leafnode = new DefaultMutableTreeNode("本机磁盘(E:)"); treeModel.insertNodeInto(leafnode, node2, node2.getChildCount()); DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("网站列表"); treeModel.insertNodeInto(node31, node3, node3.getChildCount()); leafnode = new DefaultMutableTreeNode("奇摩站"); treeModel.insertNodeInto(leafnode, node3, node3.getChildCount()); leafnode = new DefaultMutableTreeNode("职棒消息"); treeModel.insertNodeInto(leafnode, node3, node3.getChildCount()); leafnode = new DefaultMutableTreeNode("网络书店"); treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
JTree tree = new JTree(treeModel); /*改变JTree的外观**/ // tree.putClientProperty("JTree.lineStyle","Horizontal"); /*改变JTree的外观**/ JScrollPane scrollPane = new JScrollPane(); scrollPane.setViewportView(tree); contentPane.add(scrollPane); f.pack(); f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });
}
public static void main(String args[]) { new TreeDemo3(); }}
10-7:JTree的事件处理模式: 在此节中,我们将详细介绍JTree两个常用的事件与处理,分别是TreeModeEvent与TreeSelectionEvent.10-7-1:处理TreeModeEvent事件: 当树的结构上有任何改变时,例如节点值改变了、新增节点、删除节点等,都会TreeModelEvent事件,要处理这样的事件必须实作TreeModelListener界面,此界面定义了4个方法,如下所示:TreeModelListener方法:Void treeNodesChanged(TreeModelEvent e):当节点改变时系统就会云调用这个方法。Void treeNodesInserted(TreeModelEvent e):当新增节时系统就会去调用这个方法。Void treeNodesRemoved(TreeModeEvent e):当删除节点时系统就会去调用这个方法。Void treeStructureChanged(TreeModelEvent e):当树结构改变时系统就会去调用这个方法。
TreeModelEvent类本身提供了5个方法,帮我们取得事件的信息,如下所示:
TreeModelEvent方法:int[] getChildIndices():返回子节点群的索引值。Object[] getChildren():返回子节点群.Object[] getPath():返回Tree中一条path上(从root nod到leaf node)的节点。TreePath getTreePath():取得目前位置的Tree Path.String toString():取得蝗字符串表示法. 由TreeModelEvent的getTreePath()方法就可以得到TreePath对象,此对象就能够让我们知道用户目前正选哪一个节点,TreePath类最常用的方法为: public Object getLastPathComponent():取得最深(内)层的节点。 public int getPathCount():取得此path上共有几个节点. 我们来看下面这个例子,用户可以在Tree上编辑节点,按下[Enter]键后就可以改变原有的值,并将改变的值显示在下面的JLabel中:
import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.event.*;import javax.swing.tree.*;import com.incors.plaf.alloy.*;import com.incors.plaf.alloy.themes.bedouin.*;
public class TreeDemo5 implements TreeModelListener{ JLabel label = null; String nodeName = null; //原有节点名称 public TreeDemo5() { try { AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true"); AlloyTheme theme = new BedouinTheme();//设置界面的外观,手册中共有5种样式 LookAndFeel alloyLnF = new AlloyLookAndFeel(theme); UIManager.setLookAndFeel(alloyLnF); } catch (UnsupportedLookAndFeelException ex) { // You may handle the exception here } // this line needs to be implemented in order to make JWS work properly UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader()); JFrame f = new JFrame("TreeDemo"); Container contentPane = f.getContentPane(); DefaultMutableTreeNode root = new DefaultMutableTreeNode("资源管理器"); DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("文件夹"); DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的电脑"); DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夹"); DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme"); root.add(node1); root.add(node2); root.add(node3); root.add(node4); DefaultMutableTreeNode leafnode = new DefaultMutableTreeNode("公司文件"); node1.add(leafnode); leafnode = new DefaultMutableTreeNode("个人信件"); node1.add(leafnode); leafnode = new DefaultMutableTreeNode("私人文件"); node1.add(leafnode); leafnode = new DefaultMutableTreeNode("本机磁盘(C:)"); node2.add(leafnode); leafnode = new DefaultMutableTreeNode("本机磁盘(D:)"); node2.add(leafnode); leafnode = new DefaultMutableTreeNode("本机磁盘(E:)"); node2.add(leafnode); DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("网站列表"); node3.add(node31); leafnode = new DefaultMutableTreeNode("天勤网站"); node31.add(leafnode); leafnode = new DefaultMutableTreeNode("足球消息"); node31.add(leafnode); leafnode = new DefaultMutableTreeNode("网络书店"); node31.add(leafnode); JTree tree = new JTree(root); tree.setEditable(true);//设置JTree为可编辑的 tree.addMouseListener(new MouseHandle());//使Tree加入检测Mouse事件,以便取得节点名称 //下面两行取得DefaultTreeModel,并检测是否有TreeModelEvent事件. DefaultTreeModel treeModel = (DefaultTreeModel)tree.getModel(); treeModel.addTreeModelListener(this); JScrollPane scrollPane = new JScrollPane(); scrollPane.setViewportView(tree); label = new JLabel("更改数据为: "); contentPane.add(scrollPane,BorderLayout.CENTER); contentPane.add(label,BorderLayout.SOUTH); f.pack(); f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });
} /*本方法实作TreeModelListener接口,本接口共定义四个方法,分别是TreeNodesChanged() *treeNodesInserted()、treeNodesRemoved()、treeNodesRemoved()、 *treeStructureChanged().在此范例中我们只针对更改节点值的部份,因此只实作 *treeNodesChanged()方法. */ public void treeNodesChanged(TreeModelEvent e) { TreePath treePath = e.getTreePath(); System.out.println(treePath); //下面这行由TreeModelEvent取得的DefaultMutableTreeNode为节点的父节点,而不是用户点选 //的节点,这点读者要特别注意。要取得真正的节点需要再加写下面6行代码. DefaultMutableTreeNode node = (DefaultMutableTreeNode)treePath.getLastPathComponent(); try { //getChildIndices()方法会返回目前修改节点的索引值。由于我们只修改一个节点,因此节点索引值就放在index[0] //的位置,若点选的节点为root node,则getChildIndices()的返回值为null,程序下面的第二行就在处理点选root //node产生的NullPointerException问题. int[] index = e.getChildIndices(); //由DefaultMutableTreeNode类的getChildAt()方法取得修改的节点对象. node = (DefaultMutableTreeNode)node.getChildAt(index[0]); } catch (NullPointerException exc) {} //由DefaultMutableTreeNode类getUserObject()方法取得节点的内容,或是写成node.toString()亦相同. label.setText(nodeName+"更改数据为: "+(String)node.getUserObject()); } public void treeNodesInserted(TreeModelEvent e) { } public void treeNodesRemoved(TreeModelEvent e) { } public void treeStructureChanged(TreeModelEvent e) { }
public static void main(String args[]) { new TreeDemo5(); } //处理Mouse点选事件 class MouseHandle extends MouseAdapter { public void mousePressed(MouseEvent e) { try{ JTree tree = (JTree)e.getSource(); //JTree的getRowForLocation()方法会返回节点的列索引值。例如本例中,“本机磁盘(D:)”的列索引值为4,此索引值 //会随着其他数据夹的打开或收起而变支,但“资源管理器”的列索引值恒为0. int rowLocation = tree.getRowForLocation(e.getX(), e.getY());
/*JTree的getPathForRow()方法会取得从root node到点选节点的一条path,此path为一条直线,如程序运行的图示 *若你点选“本机磁盘(E:)”,则Tree Path为"资源管理器"-->"我的电脑"-->"本机磁盘(E:)",因此利用TreePath *的getLastPathComponent()方法就可以取得所点选的节点. */
TreePath treepath = tree.getPathForRow(rowLocation); TreeNode treenode = (TreeNode) treepath.getLastPathComponent(); nodeName = treenode.toString(); }catch(NullPointerException ne){} } }}
注:上面的程序MouseHandle中: int rowLocation = tree.getRowForLocation(e.getX(), e.getY()); TreePath treepath = tree.getPathForRow(rowLocation); 与: TreePath treepath=tree.getSelectionPath(); 等价,可互换。 我们将“我的电脑”改成“网上领居”: 我们再来看一个TreeModelEvent的例子,下面这个例子我们可以让用户自行增加、删除与修改节点:
import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.event.*;import javax.swing.tree.*;import com.incors.plaf.alloy.*;import com.incors.plaf.alloy.themes.bedouin.*;
public class TreeDemo6 implements ActionListener,TreeModelListener{ JLabel label=null; JTree tree=null; DefaultTreeModel treeModel=null; String nodeName=null;//原有节点名称 public TreeDemo6(){ try { AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true"); AlloyTheme theme = new BedouinTheme(); LookAndFeel alloyLnF = new AlloyLookAndFeel(theme); UIManager.setLookAndFeel(alloyLnF); } catch (UnsupportedLookAndFeelException ex) { // You may handle the exception here } // this line needs to be implemented in order to make JWS work properly UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader()); JFrame f=new JFrame("TreeDemo6"); Container contentPane=f.getContentPane(); DefaultMutableTreeNode root=new DefaultMutableTreeNode("资源管理器"); tree=new JTree(root); tree.setEditable(true); tree.addMouseListener(new MouseHandle()); treeModel=(DefaultTreeModel)tree.getModel(); treeModel.addTreeModelListener(this); JScrollPane scrollPane=new JScrollPane(); scrollPane.setViewportView(tree); JPanel panel=new JPanel(); JButton b=new JButton("新增节点"); b.addActionListener(this); panel.add(b); b=new JButton("删除节点"); b.addActionListener(this); panel.add(b); b=new JButton("清除所有节点"); b.addActionListener(this); panel.add(b); label=new JLabel("Action"); contentPane.add(panel,BorderLayout.NORTH); contentPane.add(scrollPane,BorderLayout.CENTER); contentPane.add(label,BorderLayout.SOUTH); f.pack(); f.setVisible(true); f.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); } //本方法运行新增、删除、清除所有节点的程序代码. public void actionPerformed(ActionEvent ae){ if (ae.getActionCommand().equals("新增节点")){ DefaultMutableTreeNode parentNode=null; DefaultMutableTreeNode newNode=new DefaultMutableTreeNode("新节点"); newNode.setAllowsChildren(true); TreePath parentPath=tree.getSelectionPath(); //取得新节点的父节点 parentNode=(DefaultMutableTreeNode)(parentPath.getLastPathComponent());
//由DefaultTreeModel的insertNodeInto()方法增加新节点 treeModel.insertNodeInto(newNode,parentNode,parentNode.getChildCount());
//tree的scrollPathToVisible()方法在使Tree会自动展开文件夹以便显示所加入的新节点。若没加这行则加入的新节点 //会被 包在文件夹中,你必须自行展开文件夹才看得到。 tree.scrollPathToVisible(new TreePath(newNode.getPath())); label.setText("新增节点成功"); } if (ae.getActionCommand().equals("删除节点")){ TreePath treepath=tree.getSelectionPath(); if (treepath!=null){ //下面两行取得选取节点的父节点. DefaultMutableTreeNode selectionNode=(DefaultMutableTreeNode)treepath.getLastPathComponent(); TreeNode parent=(TreeNode)selectionNode.getParent(); if (parent!=null) { //由DefaultTreeModel的removeNodeFromParent()方法删除节点,包含它的子节点。 treeModel.removeNodeFromParent(selectionNode); label.setText("删除节点成功"); } } } if (ae.getActionCommand().equals("清除所有节点")){
//下面一行,由DefaultTreeModel的getRoot()方法取得根节点. DefaultMutableTreeNode rootNode=(DefaultMutableTreeNode)treeModel.getRoot();
//下面一行删除所有子节点. rootNode.removeAllChildren();
//删除完后务必运行DefaultTreeModel的reload()操作,整个Tree的节点才会真正被删除. treeModel.reload(); label.setText("清除所有节点成功"); } } public void treeNodesChanged(TreeModelEvent e){ TreePath treePath=e.getTreePath(); DefaultMutableTreeNode node=(DefaultMutableTreeNode)treePath.getLastPathComponent(); try{ int[] index=e.getChildIndices(); node=(DefaultMutableTreeNode)node.getChildAt(index[0]); }catch(NullPointerException exc){} label.setText(nodeName+"更改数据为:"+(String)node.getUserObject()); } public void treeNodesInserted(TreeModelEvent e){ System.out.println("new node insered"); } public void treeNodesRemoved(TreeModelEvent e){ System.out.println("node deleted"); } public void treeStructureChanged(TreeModelEvent e){ System.out.println("Structrue changed"); } public static void main(String[] args){ new TreeDemo6(); } class MouseHandle extends MouseAdapter{ public void mousePressed(MouseEvent e){ try{ JTree tree=(JTree)e.getSource(); int rowLocation=tree.getRowForLocation(e.getX(),e.getY()); TreePath treepath=tree.getPathForRow(rowLocation); TreeNode treenode=(TreeNode)treepath.getLastPathComponent(); nodeName=treenode.toString(); }catch(NullPointerException ne){} } }}
10-7-2:处理TreeSelectionEvent事件: 当我们在JTree上点选任何一个节点,都会触发TreeSelectionEvent事件,如果我们要处理这样的事件,必须实作TreeSelectionListener界面,此界面只定义了一个方法,那就是valueChanged()方法。 TreeSelectionEvent最常用在处理显示节点的内容,例如你在文件图标中点两下就可以看到文件的内容。在JTree中选择节点的方式共有3种,这3种情况跟选择JList上的项目是一模一样的,分别是: DISCONTIGUOUS_TREE_SELECTION:可作单一选择,连续点选择(按住[Shift]键),不连续选择多个节点(按住[Ctrl]键),这是java默认值. CONTINUOUS_TREE_SELECTION:按住[Shift]键,可对某一连续的节点区间作选取。 SINGLE_TREE_SELECTION:一次只能选一个节点。 你可以自行实作TreeSelectionModel制作作更复杂的选择方式,但通常是没有必要的,因为java提供了默认的选择模式类供我们使用,那就是DefaultTreeSelectionModel,利用这个类我们可以很方便的设置上面3种选择模式。 下面这个范例,当用户点选了一个文件名时,就会将文件的内容显示出来。TreeDemo7.java
import javax.swing.*;import javax.swing.tree.*;import javax.swing.event.*;import java.awt.*;import java.awt.event.*;import java.io.*;import java.util.*;import com.incors.plaf.alloy.*;import com.incors.plaf.alloy.themes.glass.*;
public class TreeDemo7 implements TreeSelectionListener{ JEditorPane editorPane;
public TreeDemo7() { JFrame f = new JFrame("TreeDemo"); Container contentPane = f.getContentPane(); DefaultMutableTreeNode root = new DefaultMutableTreeNode("资源管理器"); DefaultMutableTreeNode node = new DefaultMutableTreeNode("TreeDemo1.java"); root.add(node); node = new DefaultMutableTreeNode("TreeDemo2.java"); root.add(node); node = new DefaultMutableTreeNode("TreeDemo3.java"); root.add(node); node = new DefaultMutableTreeNode("TreeDemo4.java"); root.add(node); JTree tree = new JTree(root); //设置Tree的选择模式为一次只能选择一个节点 tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); //检查是否有TreeSelectionEvent事件。 tree.addTreeSelectionListener(this);
//下面五行,JSplitPane中,左边是放含有JTree的JScrollPane,右边是放JEditorPane. JScrollPane scrollPane1 = new JScrollPane(tree); editorPane = new JEditorPane(); JScrollPane scrollPane2 = new JScrollPane(editorPane); JSplitPane splitPane = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT,true, scrollPane1, scrollPane2);
contentPane.add(splitPane); f.pack(); f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } //本方法实作valueChanged()方法 public void valueChanged(TreeSelectionEvent e) { JTree tree = (JTree) e.getSource(); //利用JTree的getLastSelectedPathComponent()方法取得目前选取的节点. DefaultMutableTreeNode selectionNode = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
String nodeName = selectionNode.toString(); //判断是否为树叶节点,若是则显示文件内容,若不是则不做任何事。 if (selectionNode.isLeaf()) { /*取得文件的位置路径,System.getProperty("user.dir")可以取得目前工作的路径, *System.getProperty("file.separator")是取得文件分隔符,例如在window环境的 *文件分陋符是"/",而Unix环境的文件分隔符刚好相反,是"/".利用System.getProperty() *方法你可以取得下列的信息: java.version 显示java版本 java.endor 显示java制造商 java.endor.url 显示java制造商URL java.home 显示java的安装路径 java.class.version 显示java类版本 java.class.path 显示java classpath os.name 显示操作系统名称 os.arch 显示操作系统结构,如x86 os.version 显示操作系统版本 file.separator 取得文件分隔符 path.separator 取得路径分隔符,如Unix是以“:”表示 line.separator 取得换行符号,如Unix是以"/n"表示 user.name 取得用户名称 user.home 取得用户家目录(home directory),如Windows中Administrator的家目 录为c:/Documents and Settings/Administrator user.dir 取得用户目前的工作目录. */ String filepath = "file:"+System.getProperty("user.dir") + System.getProperty("file.separator") + nodeName; try { //利用JEditorPane的setPage()方法将文件内容显示在editorPane中。若文件路径错误,则会产生IOException. editorPane.setPage(filepath); } catch(IOException ex) { System.out.println("找不到此文件"); } } } public static void main(String[] args) { SwingUtil.setLookAndFeel(); new TreeDemo7(); }}
class SwingUtil{ public static final void setLookAndFeel() { try{ Font font = new Font("JFrame", Font.PLAIN, 12); Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
while (keys.hasMoreElements()) { Object key = keys.nextElement(); if (UIManager.get(key) instanceof Font) { UIManager.put(key, font); } } AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true"); AlloyTheme theme = new GlassTheme(); LookAndFeel alloyLnF = new AlloyLookAndFeel(theme); JFrame.setDefaultLookAndFeelDecorated(true); UIManager.setLookAndFeel(alloyLnF); }catch(UnsupportedLookAndFeelException ex){ ex.printStackTrace(); }}}