📄 s20.htm
字号:
<SCRIPT LANGUAGE="JavaScript" SRC="/-fs0/sys/pop-up.js"></SCRIPT><SCRIPT LANGUAGE="JavaScript" SRC="/-fs0/sys/pop-up-all.js"></SCRIPT><html><head><title>易都网--Java 2 图形设计卷Ⅱ:SWING</title><LINK rel="stylesheet" href="../../../_public/javaa.css"><meta http-equiv="Content-Type" content="text/html; charset=GBK"><script language="JavaScript" src="../../../_public/javaa.js"></script><meta name="keywords" content="Java,JSP,ASP,PHP,J2EE,EJB,JavaScript,C/C++,ASM,CSS,HTML,XML,网络安全,MySQL,ACCESS"></head><body bgcolor="#FFFFFF"><table border=0 cellpadding=0 cellspacing=0 width="100%"> <tbody> <script language="javascript">print2()</script> <tr> <td width="100%"> <table bgcolor=#EEEEEE border=0 cellpadding=3 cellspacing=0 width="100%"> <tbody> <tr> <td class=f1 id=thetd width="100%"> <p>[<a href="index.html" target="_self">目录</a>][<a href="s19.htm">上一页</a>][<a href="s21.htm">下一页</a>]</p> <p align="center"><b>第20章 树</b></p> <p> Swing树使用人们所熟悉的文件夹和树叶图来显示分层的数据。应用最广泛的树组件(树组件又称为轮廓控件)。无疑是Windows Explorer,它包含一个用于导航目录的树组件。<br> 与表格类似,树由许多类和接口组成,这些类和接口在它们自己的包——swing.tree包中定义,swing包中的JTree类代表树组件。<br> 树由节点组成,节点可以是文件夹,也可以是树叶。文件夹可以有子节点,除根节点之外的所有节点都只有一个父节点。空的文件夹与树叶的不同之处就在于它允许有子节点。<br> 图20-1显示的是JTree类的一个扩展,该扩展可用于导航目录和文件。文件夹和树叶由不同的图标表示,这些图标都是彼此独立的。在文件夹上双击,或单击文件夹的句柄,就可以展开或折叠文件夹,根节点句柄的可见性可以被设置。例如,图20-1所示的树的根节点就没有显示句柄。<br> 除父节点和子节点外,树的节点还有一个用户对象(当使用DefaultTreeModel时就会呈现一个用户对象)。用户对象是Object类型,因此它提供了一个将任意对象与节点相关联的办法。<br> 树有一个简单的模型,每一个JTree实例都要维护对绘制器和编辑器的引用,这个绘制器和编辑器被树中所有的节点所使用。在表20-1中列出了swing.tree包中的主要类。</p> <p> <b>表20-1 Swing.tree包中的主要类</b><br> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━<br> <b>名 称</b> <b>实 现</b><br> ─────────────────────────────────<br> DefaultMutableTreeNode 一个具有一个父节点、(可能)许多子节点和<br> 一个用户对象的可变节点,为相关联的节点提<br> 供了访问方法。如果没有任何子节点,这个节<br> 点就是树叶<br> DefaultTreeModel 一个激发TreeModel Events事件的简单可变的模型。<br> 提供对子节点的访问方法,但不是提供对父节点的访<br> 问方法 <br> DefaultTreeCellEditor 绘制器和编辑器的包装器,它把一个“真正”的<br> 编辑器组件放在节点图标的旁边 <br> DefaultTreeCellRenderer 具有字体、颜色和图标访问方法的JLabel扩<br> 展,它提供图标的缺省值<br> TreePath 由一个节点到另一个节点的路径。路径中的节点存储在一个数<br> 组中。路径用于在选取内容之间进行通信<br> ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ </p> <p> <b>20.1 创建树</b></p> <p> <a href="s20_t02.htm" target="_blank">图20-2</a>示出的小应用程序包含一个表格,这个表格是用JTree无参数构件方法创建的。<br> 图20-2中所示的小应用程序向应用程序的内容空格中添加了一个树,这个树包裹在一个滚动空格中。在例20-1中列出了这个小应用程序的代码。在缺省情况下显示一个树中所示的树在程序开始运行时,它的文件夹都是展开的。</p> <p> <b>例20-1 一个简单的树的例子</b><br> ─────────────────────────────────<br> import javax.swing.*;<br> public class Test extends JApplet {<br> public void init(){<br> getContentPane().add(new JScrollPane(new JTree()));<br> }<br> } <br> ─────────────────────────────────</p> <p> 如果在构造时没有显式地指定模型或节点,则JTree的实例就以图20-2所示的节点来构造。<br> 几乎所有的树都是以下面的方式来构造的:选创建一个根节点,然后建立分层结构或创建一个树模型。例如,在创建图20-2所示的节点的缺省分层结构时,JTree缺省的构造方法就调用了JTree.getDefaultTreeModel()。<br> //From JTree.java:<br> protected static TreeModel getDefaultTreeModel(){<br> DefaultMutableTreeNode root=<br> new Default Mutable Tree Node ("JTree");<br> DefaultMutableTreeNode parent;</p> <p> parent = new DefaultMutableTreeNode("colors");<br> root.add(parent);<br> parent.add(new DefaultMutableTreeNode("blue"));<br> parent.add(new DefaultMutableTreeNode("violet"));<br> parent.add(new DefaultMutableTreeNode("red"));<br> parent.add(new DefaultMutableTreeNode("yellow"));</p> <p> parent = new DefaultMutableTreeNode("sports");<br> root.add(parent);<br> parent.add(new DefaultMutableTreeNode("basketball"));<br> parent.add(new DefaultMutableTreeNode("soccer"));<br> parent.add(new DefaultMutableTreeNode("football"));<br> parent.add(new DefaultMutableTreeNode("hockey"));<br> ...<br> return new DefalutTreeModel(root);<br> }</p> <p></p> <p> 用户对象的带有字符串JTree的节点被实例化,而且最终指定为树模型的根节点,节点colors有四个子节点,且指定为根节点的唯一节点。节点sports也有四个节点,而且也被添加到根节点中。<br> JTree类还提供了用Object数组、哈希表和矢量创建树的构造方法,如<a href="s20_t03.htm" target="_blank">图20-3</a>所示。<br> 与构造分层节点相比,用数据来构造树,需要注意两点:<br> 第一点,数据很少(几乎没有)用来构造树,通常,树都是用节点一配置的,图20-2中所示的小应用程序即是一例。<br> 第二点,由于对象添加到哈希表中的顺序和对象在哈希表中存放的顺序没有任何联系,因此,用哈希表创建的树的节点顺序是难以预料的。<br> 例20-2列出了图20-3中所示小应用程序的完整代码。<br> <b>例20-2用对象、矢量和哈希表来创建树</b><br> ─────────────────────────────────<br> import javax.swing.*;<br> import javax.swing.tree.TreePath;<br> import java.awt.*;<br> import java.awt.event.*;<br> import java.util.*;</p> <p> public class Test extends JApplet {<br> Hashtable ht = new Hashtable(), ht2 = new Hashtable();<br> Vector vector = new Vector();<br> Object[] objs = new Object[] {<br> "array item 1", "array item 2", "array item 3" <br> };<br> public void init() {<br> Container contentPane = getContentPane();</p> <p> vector.addElement("vector element 1");<br> vector.addElement("vector element 2");<br> vector.addElement("vector element 3");<br> vector.addElement("vector element 4");<br> vector.addElement("vector element 5");</p> <p> ht.put("another hashtable", ht2);<br> ht.put("vector", vector);<br> ht.put("Object[]", objs);</p> <p> ht2.put("Object[]", objs);<br> ht2.put("vector", vector);<br> ht2.put("one", new Integer(1));<br> ht2.put("two", new Integer(2));<br> ht2.put("three", new Integer(3));</p> <p> // trees must be created after data is populated</p> <p> JTree hashTree = new JTree(ht);<br> JTree vectorTree = new JTree(vector);<br> JTree objectTree = new JTree(objs);</p> <p> JScrollPane objPane = new JScrollPane(objectTree);<br> JScrollPane hashPane = new JScrollPane(hashTree);<br> JScrollPane vectorPane = new JScrollPane(vectorTree);</p> <p> objPane.setPreferredSize(new Dimension(150,200));//w,h<br> hashPane.setPreferredSize(new Dimension(250,200));<br> vectorPane.setPreferredSize(new Dimension(150,200));</p> <p> objPane.setBorder(<br> BorderFactory.createTitledBorder("Object[]"));</p> <p> hashPane.setBorder(<br> BorderFactory.createTitledBorder("Hashtable"));</p> <p> vectorPane.setBorder(<br> BorderFactory.createTitledBorder("Vector"));</p> <p> hashTree.expandPath(new TreePath(<br> hashTree.getModel().getRoot())); </p> <p> contentPane.setLayout(new FlowLayout());<br> contentPane.add(objPane);<br> contentPane.add(hashPane);<br> contentPane.add(vectorPane);<br> }<br> }<br> ─────────────────────────────────<br> </p> <p> <b>20.2 树节点</b></p> <p> 在Swing树中,树节点是关键的组成部分,如同列是表格的主干一样。树节点由TreeNode接口定义,TreeNode接口被MutableTreeNode接口扩展,而MutableTreeNode接口又由DefaultMutableTreeNode类来实现。</p> <p> <b>20.2.1 TreeNode接口</b></p> <p> TreeNode接口定义了(固定)树节点的实质,接口总结20-1总结了树节点。<br> </p> <table width="100%" border="1" cellspacing="0" cellpadding="0" bgcolor="#CCCCCC" bordercolorlight="#000000" bordercolordark="#FFFFFF"> <tr> <td><b>接口总结20-1 TreeNode</b></td> </tr> </table> <p> public abstract Enumeration children()<br> public abstract TreeNode getParent()<br> public abstract TreeNode getChildAt(int)<br> public abstract int getChildCount()<br> public abstract int getIndex(TreeNode)<br> public abstract abstract boolean getAllowsChildren()<br> public abstract boolean isLeaf()<br> 上面列出的前两组方法是对一个节点的父节点和子节点的访问方法。访问一个节点的子节点,可以通过枚举子节点的父节点来实现,也可以通过索引来访问子节点。另外,还定义了获取节点索引的方法和获取一个节点包含的子节点数目的方法。<br> 上面列出的最后两个方法用来确定一个节点是文件夹,还是树叶。 </p> <hr size="1" noshade> <p> 开发人员很少直接实现TreeNode接口,这是因为Swing在DefaultMutableTreeNode类中提供了TreeNode接口的一个常用的缺省实现。数目众多的树节点扩展了DefaultMutableTreeNode。 </p> <p> <b>20.2.2 MutableTreeNode接口</b></p> <p> MutableTreeNode接口扩展TreeNode,它除了定义指定用户对象的方法外,还定义了修改一个节点的父节点和子节点的方法。接口总结20-2总结了MutableNode接口。<br> </p> <table width="100%" border="1" cellspacing="0" cellpadding="0" bgcolor="#CCCCCC" bordercolorlight="#000000" bordercolordark="#FFFFFF"> <tr> <td><b>接口总结20-2 MutableTreeNode</b></td> </tr> </table> <p> 扩展:TreeNode<br> public abstract void insert(MutableTreeNode child,int index)<br> public abstract void remove(int index)<br> public abstract void remove(MutableTreeNode child)<br> public abstract void removeFromParent()<br> public abstract void setParent(MutableTreeNode)<br> public abstract void setUserObject(Object)<br> 上面列出的第一组方法用来插入和删除子节点,子节点可以通过索引或引用来删除。removeFromParent方法用来将节点从父节点中删除,并更新父节点的子节点数目。<br> 上面列出的最后两个方法用来设置一个节点的父节点和用户对象。需要注意的是,MutableTreeNode继承了getParent方法,而没有继承getUserObject方法,这是一个疏漏,在以后发布的Swing中将予以更正。在实际应用中,因为没有getUserObject方法而造成的影响几乎为零,这是因为该方法已在defaultMutableTreeNode类中得到了实现。 </p> <hr size="1" noshade> <p><b>20.2.3 DefaultMutableTreeNode类</b></p> <p> 在实际应用各,很少直接实现MutableTreeNode接口,这是因为Swing以DefaultMutableTreeNode类的形式提供了一个合理又强壮的MutableTreeNode接口的实现。<br> 图20-4示出了DefaultMutableTreeNode接口,并维护对其父节点、用户对象和子节点的引用。通过维护对其父节点和子节点的一个引用,DefaultMutableTreeNode类实现了组合设计样式(注:内容略),该样式允许对文件夹和树叶进行嵌套。AWT的Component类Container类也是组合设计样式的一个样例(注:内容略)。<br> 1.使用DefaultMutableTreeNode<br> 树节点几乎总是DefaultMutableTreeNode类的实例或它的扩展。例如,由一个树创建的缺省节点就是DefaultMutableTreeNode的实例。<br> 除了那些在TreeNode和MutableTreeNode接口中定义的方法外,DefaultMutableTreeNode类还提供了许多其他的方法来访问相关的节点。例如,它提供了getFirstLeaf和getNextLeaf方法,前一种方法返回第一个树叶,第二种方法返回某一个给定树叶的下一个兄弟节点。<br> DefaultMutableTreeNode类还提供了一些方法,这些方法以尝试优先或宽度优先遍历方式来返回由一个节点派生的子节点的一个枚举,深度优先和宽度优先这两种遍历方式的区别同图20-5。例20-3的小应用程序显示树的节点,这些节点是通过对一个树的根节点调用DefaultMutableTreeNode.depthFirstEmumeration和DefaultMutableTreeNode.breadthFirstEnumeration来获取的。</p> <p align="center"> <b>例20-3 深度优先遍历与宽度优先遍历之间的比较</b></p> <hr size="1" noshade> import java.awt.*;<br> import java.awt.event.*;<br> import javax.swing.*;<br> import javax.swing.tree.*;<br> import java.util.*;<p> public class Test extends JApplet {<br> private JTree tree = new JTree();<br> private JButton button = new JButton("show traversals");</p> <p> private DefaultMutableTreeNode root = <br> (DefaultMutableTreeNode)tree.getModel().getRoot();</p> <p> public void init() {<br> getContentPane().add(new JScrollPane(tree), <br> BorderLayout.CENTER);<br> getContentPane().add(button, BorderLayout.NORTH);</p> <p> button.addActionListener(new ActionListener() {<br> public void actionPerformed(ActionEvent e) {<br> Enumeration df = root.depthFirstEnumeration();<br> Enumeration bf = root.breadthFirstEnumeration();</p> <p> while(df.hasMoreElements()) {<br> System.out.println(<br> df.nextElement().toString());<br> }</p> <p> System.out.println("");<br> System.out.println("");</p> <p> while(bf.hasMoreElements()) {<br> System.out.println(<br> bf.nextElement().toString());<br> }</p> <p> }<br> });<br> }<br> }</p> <hr size="1" noshade> <p> 2.扩展DefaultMutableTreeNode<br> 可能对目录和文件提供导航的文件查看器可能是树组件最自然的应用,图20-6所示的应用程序就包含一个可用作文件查看器的JTree的一个实例。<br> Swing树的设计基本是简便易行的,图20-6所示的应用程序就是一个证明,它有一个简单的实现方法。树包含有定制节点,这些节点是FileNode类的一些实例,而FileNode类维护作为自己的用户对象的一个File实例。 </p> <p> </p> <p> </p> <p> </p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -