12.10 使用JTree和TreeModel创建树 12.10.1 创建树
12.10 使用JTree和TreeModel创建树
树也是图形用户界面中使用非常广泛的GUI
组件,例如使用Windows
资源管理器时,将看到如图12.38所示的目录树。
如图12.38所示的树,代表计算机世界里的树,它从自然界实际的树抽象而来。计算机世界里的树是由一系列具有严格父子关系的节点组成的,每个节点既可以是其上一级节点的子节点,也可以是其下一级节点的父节点,因此同一个节点既可以是父节点,也可以是子节点(类似于一个人,他既是他儿子的父亲,又是他父亲的儿子)。
节点分类
如果按节点是否包含子节点来分,节点分为如下两种
- 普通节点:包含子节点的节点。
- 叶子节点:没有子节点的节点,因此叶子节点不可作为父节点。
如果按节点是否具有唯一的父节点来分,节点又可分为如下两种
- 根节点:没有父节点的节点,根节点不可作为子节点。
- 普通节点:具有唯一父节点的节点。
棵树只能有一个根节点,如果一棵树有了多个根节点,那它就不是一棵树了,而是多棵树的集合,有时也被称为森林。图12.39显示了计算机世界里树的一些专业术语。
使用Swing
里的JTree
、TreeModel
及其相关的辅助类可以很轻松地开发出计算机世界里的树,如图1239所示
12.10.1 创建树
Swing
使用JTree
对象来代表一棵树(实际上,JTree
可以代表森林,因为在使用JTree
创建树时可以传入多个根节点),JTree
树中节点可以使用TreePath
来标识,**TreePath
对象封装了当前节点及其所有的父节点。必须指出,节点及其所有的父节点才能唯一地标识一个节点**;也可以使用行数来标识,如图12.39所示,显示区域的每一行都标识一个节点。
当一个节点具有子节点时,该节点有两种状态。
- 展开状态:当父节点处于展开状态时,其子节点是可见的。
- 折叠状态:当父节点处于折叠状态时,其子节点都是不可见的。
如果某个节点是可见的,则该节点的父节点(包括直接的、间接的父节点)都必须处于展开状态,只要有任意一个父节点处于折叠状态,该节点就是不可见的。
如果希望创建一棵树,则直接使用JTree
的构造器创建JTree
对象即可。JTree
提供了如下几个常用构造器。
方法 | 描述 |
---|---|
JTree(TreeModel newModel) |
使用指定的数据模型创建JTree 对象,它默认显示根节点。 |
JTree(TreeNode root) |
使用root 作为根节点创建JTree 对象,它默认显示根节点。 |
JTree(TreeNode root, boolean asksAllowsChildren) |
使用root 作为根节点创建JTree 对象,它默认显示根节点。**asksAllowsChildren 参数控制怎样的节点才算叶子节点**:
|
上面的第一个构造器需要显式传入一个TreeModel
对象,Swing
为TreeModel
提供了一个DefaultTreeModel
实现类,通常可先创建DefaultTreeModel
对象,然后利用DefaultTreeModel
来创建JTree
,但通过DefaultTreeModel
的API
文档会发现,创建DefaultTreeModel
对象依然需要传入根节点,所以直接通过根节点创建JTree
更加简洁。
为了利用根节点来创建JTree
,程序需要创建一个TreeNode
对象。TreeNode
是一个接口,该接口有个MutableTreeNode
子接口,Swing
为该接口提供了默认的实现类:DefaultMutableTreeNode
,程序可以通过DefaultMutableTreeNode
来为树创建节点,并通过DefaultMutableTreeNode
提供的add()
方法建立各节点之间的父子关系,然后调用JTree
的JTree(TreeNodeRoot
构造器来创建一棵树。
图12.40显示了JTree
相关类的关系,从该图可以看出DefaultTreeModel
是TreeModel
的默认实现类,当程序通过TreeNode
类创建JTree
时,其状态数据实际上由DefaultTreeModel
对象维护,因为创建JTree
时传入的TreeNode
对象,实际上传给了DefaultTreeModel
对象。
DefaultTreeModel
也提供了DefaultTreeModel(TreeNode root)
构造器,用于接收一个TreeNode
根节点来创建一个默认的TreeModel
对象;当程序中通过传入一个根节点来创建JTree
对象时,实际上是将该节点传入对应的DefaultTreeModel
对象,并使用该DefaultTreeModel
对象来创建JTree
对象
程序 简单Swing数组
下面程序创建了一棵最简单的Swing
树:
1 | import javax.swing.*; |
上面程序中的粗体字代码创建了一系列的DefaultMutableNode
对象,并通过add()
方法为这些节点建立了相应的父子关系。程序中①号代码则以一个根节点创建了一个JTree
对象。当程序把JTree
对象添加到其他容器中后,JTree
就会在该容器中绘制出一棵Swing
树。运行上面程序,会看到如图12.41所示的窗口。
从图12.41中可以看出,Swing
树的默认风格是使用一个特殊图标来表示节点的展开、折叠,而不是使用我们熟悉的“+”、“-”图标来表示节点的展开、折叠。如果希望使用“+”、“-”图标来表示节点的展开、折叠,则可以考虑使用Windows
风格。
不显示节点之间的连线
从图12.41中可以看出,Swing
树默认使用连接线来连接所有节点,程序可以使用如下代码来强制JTree
不显示节点之间的连接线。
1 | //没有连接线 |
只有水平分割线
或者使用如下代码来强制节点之间只有水平分隔线。
图12.41中显示的根节点前没有绘制表示节点展开、折叠的特殊图标,如果希望根节点也绘制表示节点展开、折叠的特殊图标,则使用如下代码。
1 | //设置是否显示根节点的“展开、折叠”图标,默认是fase |
隐藏根节点
JTree
甚至允许把整个根节点都隐藏起来,可以通过如下代码来隐藏根节点。
1 | //设置根节点是否可见,默认是true |
遍历所有子节点
DefaultMutableTreeNode
是JTree
默认的树节点,该类提供了大量的方法来访问树中的节点,包括遍历该节点的所有子节点的两个方法。
方法 | 描述 |
---|---|
Enumeration<TreeNode> breadthFirstEnumeration() |
按广度优先的顺序遍历以此节点为根的子树,并返回所有节点组成的枚举对象。 |
Enumeration<TreeNode> preorderEnumeration() |
Creates and returns an enumeration that traverses the subtree rooted at this node in preorder. |
Enumeration<TreeNode> depthFirstEnumeration() |
按深度优先的顺序遍历以此节点为根的子树,并返回所有节点组成的枚举对象。 |
Enumeration<TreeNode> postorderEnumeration() |
Creates and returns an enumeration that traverses the subtree rooted at this node in postorder. |
获取节点
除此之外,DefaultMutableTreeNode
也提供了大量的方法来获取指定节点的兄弟节点、父节点节点等,常用的有如下几个方法:
方法 | 描述 |
---|---|
DefaultMutableTreeNode getNextSibling() |
返回此节点的下一个兄弟节点 |
TreeNode getParent() |
返回此节点的父节点。如果此节点没有父节点,则返回null |
TreeNode[] getPath() |
返回从根节点到达此节点的所有节点组成的数组。 |
protected TreeNode[] getPathToRoot(TreeNode aNode, int depth) |
返回包含此节点的树的根节点。 |
DefaultMutableTreeNode getPreviousSibling() |
返回此节点的上一个兄弟节点。 |
TreeNode getRoot() |
返回包含此节点的树的根节点 |
TreeNode getSharedAncestor(DefaultMutableTreeNode aNode) |
返回此节点和aNode 最近的共同祖先 |
int getSiblingCount() |
返回此节点的兄弟节点数 |
boolean isLeaf() |
返回该节点是否是叶子节点。 |
boolean isNodeAncestor(TreeNode anotherNode) |
判断anotherNode 是否是当前节点的祖先节点(包括父节点)。 |
boolean isNodeChild(TreeNode aNode) |
如果aNode 是此节点的子节点,则返回true |
boolean isNodeDescendant(DefaultMutableTreeNode anotherNode) |
如果anotherNode 是此节点的后代,包括是此节点本身、此节点的子节点或此节点的子节点的后代,都将返回tnue 。 |
boolean isNodeRelated(DefaultMutableTreeNode aNode) |
当aNode 和当前节点位于同一棵树中时返回true 。 |
boolean isNodeSibling(TreeNode anotherNode) |
返回anotherNode 是否是当前节点的兄弟节点。 |
boolean isRoot() |
返回当前节点是否是根节点。 |
Enumeration<TreeNode> pathFromAncestorEnumeration(TreeNode ancestor) |
返回从指定祖先节点到当前节点的所有节点组成的枚举对象 |