JTree简介

同JTable类似,JTree也是一个负责的组件,其周围也有大量附属接口、类,如下图所示:

一.TreeNode(树节点)

TreeNode是JTree的核心组成部分,通过TreeNode实现了Tree的基本结构。

swing提供了三个相关的接口和类。

                                     

接口总结20-1 TreeNode

public abstract Enumeration children()  —— 枚举children
  public abstract TreeNode getParent()  —— 获取父节点
  public abstract TreeNode getChildAt(int) —— 每个节点都有index,根据index获取节点
  public abstract int getChildCount()     —— children数量
  public abstract int getIndex(TreeNode)  —— 根据节点获取index
  public abstract boolean getAllowsChildren()
  public abstract boolean isLeaf()
  最后两个方法用来确定一个节点是文件夹,还是树叶:

(1)         isLeaf()——只要此节点没有children,就返回true;

(2)         getAllowsChildren()——表示是否可以拥有children,而不是目前是否拥有children。

接口总结20-2 MutableTreeNode

扩展:TreeNode
  public abstract void insert(MutableTreeNode child, int index)
  public abstract void remove(int index)
  public abstract void remove(MutableTreeNode child)
  public abstract void removeFromParent()
  public abstract void setParent(MutableTreeNode)
  public abstract void setUserObject(Object)
  上面列出的第一组方法用来插入和删除子节点,子节点可以通过索引或引用来删除。removeFromParent方法用来将节点从父节点中删除,并更新父节点的子节点数目。
  上面列出的最后两个方法用来设置一个节点的父节点和用户对象(UserObject)。

一般情况下,UserObject是构成“树节点”的“业务”数据,比如,该节点记录了Integer、double、或String,则userObject就分别是这三种Object。比如,DefaultMutableTreeNode就定义了两个使用UserObject来进行初始化的构造函数。

DefaultMutableTreeNode类

开发人员很少直接实现TreeNode接口,这是因为Swing在DefaultMutableTreeNode类中提供了TreeNode接口的一个常用的缺省实现。数目众多的树节点扩展了DefaultMutableTreeNode。

构造方法摘要

DefaultMutableTreeNode() 
          创建没有父节点和子节点的树节点,该树节点允许有子节点。

 

DefaultMutableTreeNode(Object userObject)
         创建没有父节点和子节点、但允许有子节点的树节点,并使用指定的用户对象对它进行初始化。

 

DefaultMutableTreeNode(Object userObject, boolean allowsChildren)
 创建没有父节点和子节点的树节点,使用指定的用户对象对它进行初始化,仅在指定时才允许有子节点。

 

 

除了接口定义的各种方法外,该类还实现了一些其他的方法,方便使用:

 void

add(MutableTreeNode newChild)
          从其父节点移除 newChild,并通过将其添加到此节点的子数组的结尾,使其成为此节点的子节点。

 TreeNode

getFirstChild() 
          返回此节点的第一个子节点。

DefaultMutableTreeNode

getFirstLeaf() 
          查找并返回为此节点后代的第一个叶节点,即此节点或其第一个子节点的第一个叶节点。

 TreeNode

getLastChild() 
          返回此节点的最后一个子节点。

 DefaultMutableTreeNode

getLastLeaf() 
          查找并返回为此节点后代的最后一个叶节点,即此节点或其最后一个子节点的最后一个叶节点。

 DefaultMutableTreeNode

getNextLeaf() 
          返回此节点后面的叶节点,如果此节点是树中的最后一个叶节点,则返回 null。

DefaultMutableTreeNode

getNextNode() 
          返回在此节点的树的前序遍历中此节点之后的节点。

 TreeNode[]

getPath() 
          返回从根到达此节点的路径。

 Object

getUserObject() 
          返回此节点的用户对象。

 

JTree的TreeNode设计非常成功,比如,swing.pdf有一个例子,扩展DefaultMutableTreeNode实现文件导航器,短短几十行代码就完成了,十分的漂亮。

二.TreePath(树路径)

TreePath类表示TreeNode的路径,它的内部实现其实是一个Objects 数组,每个成员都是一个TreeNode。

一般来说,我们不直接生成TreePath,而是通过TreeNode实现类(如DefaultMutableTreeNode)获取Path。

 

方法摘要

 Object

getLastPathComponent() 
          返回此路径的最后一个组件。

          (即节点自身)

 TreePath

getParentPath() 
          返回包含除最后一个路径组件之外的此对象所有元素的路径。

          (即父节点的路径)

 Object[]

getPath() 
          返回有序的 Objects 数组,它包含此 TreePath 的组件。

 Object

getPathComponent(int element) 
          返回指定索引位置的路径组件。

 int

getPathCount() 
          返回路径中的元素数。

 boolean

isDescendant(TreePath aTreePath)
          如果 aTreePath 为此 TreePath 的后代,则返回 true。

 TreePath

pathByAddingChild(Object child)
          返回包含此对象的所有元素加上 child 的新路径。

 boolean

equals(Object o)
       
   通过检查路径中每个元素的相等性,测试两个 TreePaths 的相等性。


三.TreeModel(树模型)

同JTable相比,TreeModel接口显得不那么重要。这是Tree的特殊性造成的——TreeNode实现Tree的物理结构。因此,TreeModel接口中最重要的作用就是跟踪Tree的根节点了。

方法摘要

 Object

getRoot() 
          返回树的根。

 boolean

isLeaf(Object node)
          如果 node 为叶节点,则返回 true。

 void

addTreeModelListener(TreeModelListener l)
          为树更改后发布的 TreeModelEvent 添加侦听器。

 Object

getChild(Object parent, int index)
          返回父节点的子数组中索引 index 位置的 parent 的子节点。

 int

getChildCount(Object parent)
          返回 parent 的子节点数。

 int

getIndexOfChild(Object parent,Object child) 
          返回父节点中子节点的索引。

 void

removeTreeModelListener(TreeModelListener l)
          移除以前通过 addTreeModelListener 添加的侦听器。

 void

valueForPathChanged(TreePath path,Object newValue) 
          用户已将 path 标识的项的值更改为 newValue 时,进行通知。

 

Swing定义了DefaultTreeModel实现TreeModel接口,它还额外实现了许多方法:

 boolean

asksAllowsChildren() 
告知如何确定叶节点。如果只有不允许有子节点的节点是叶节点,则返回 true,如果没有子节点的节点(即使允许)是叶节点,则返回 false

 void

setAsksAllowsChildren(boolean newValue)
 通过向 TreeNodes 询问 getAllowsChildren() 或 isLeaf(),设置是否测试无叶性。

 void

setRoot(TreeNode root)
          将根设置为 root。

 TreeNode[]

getPathToRoot(TreeNode aNode)
          向上构建节点的父节点一直到根节点(包括根节点),其中原始节点是返回数组中的最后一个元素。

protected  TreeNode[]

getPathToRoot(TreeNode aNode, int depth)
          向上构建节点的父节点一直到根节点(包括根节点),其中原始节点是返回数组中的最后一个元素。

 void

insertNodeInto(MutableTreeNode newChild,MutableTreeNode parent, int index)
          对它进行调用,以便在父节点的子节点中的 index 位置插入 newChild

 void

removeNodeFromParent(MutableTreeNode node)
          通知它从其父节点中移除节点。

 

值得一提的是TreeModelEvent,在节点更改、插入或移除时会触发此事件。

此时,Tree节点的修改已经完成:

(1)         即如果是添加的话,新添加节点已经添加好;

(2)         删除的话,已经被删除(通过该节点的getParent()无法得到父节点了,可以通过e.getPath()得到“原父节点”)

方法摘要

 Object[]

getPath() 
    返回的是“已修改、添加、删除”的节点的父节点的路径。

 int[]

getChildIndices() 
     返回“被修改节点”相对于其“原/新”父节点的子索引值。

 Object[]

getChildren() 
     返回被修改的节点本身。

 TreePath

getTreePath() 
          对于除 treeStructureChanged 以外的所有事件,返回已更改节点的父节点。

 

【注】:除了ModelStructure整个改变之外,TreeModelEvent仅支持一个节点的修改(修改、删除、添加)。

当我们选取多个节点进行操作时,其实是依次激发多个TreeModelEvent。

四.TreeSelectionModel(树选取模型)

接口TreeSelectionModel的JAVA help描述如下:

此接口表示树选择组件的当前状态。有关使用树选择模型的信息和示例,请参阅 The Java Tutorial 中的How to Use Trees 一节。

树选择的状态由 TreePath 集合描述,也可以是整数集合。从 TreePath 到整数的映射通过 RowMapper 实例的方式完成。TreeSelectionModel 不一定具有 RowMapper 才可以正确地操作,但是,没有 RowMapper 的情况下,getSelectionRows 将返回 null。

可以将 TreeSelectionModel 配置为只允许一条路径 (SINGLE_TREE_SELECTION)、多条连续路径 (CONTIGUOUS_TREE_SELECTION) 或多条不连续的路径 (DISCONTIGUOUS_TREE_SELECTION)。RowMapper 用于确定 TreePath 是否为连续。没有 RowMapper 时,CONTIGUOUS_TREE_SELECTION 和 DISCONTIGUOUS_TREE_SELECTION 的功能相同,即都允许在 TreeSelectionModel 中包含任何数量的路径。

对于 CONTIGUOUS_TREE_SELECTION 选择模型,路径在任何时候更改时(通过 setSelectionPath、addSelectionPath ...),都将重新检查 TreePath,以使它们保持连续。通过调用 resetRowSelection,也可以强制检查 TreePath。如何将一组不连续的 TreePath 映射到连续集合要通过此实例的实现者强制执行特定的策略来完成。

实现应对添加到该选择中的重复 TreePath 进行组合。例如,以下代码

   TreePath[] paths = new TreePath[] { treePath, treePath };

   treeSelectionModel.setSelectionPaths(paths);

 

会导致仅选择一个路径:treePath,而不是 treePath 的两个副本。

前导 TreePath 是添加(或设置)的最后一个路径。前导行则是对应于 TreePath 的行,由 RowMapper 确定。

 

重要的方法有:

 void

addPropertyChangeListener(PropertyChangeListener listener)
          将一个 PropertyChangeListener 添加到侦听器列表中。

 void

addTreeSelectionListener(TreeSelectionListener x)
          向侦听器列表添加 x,每次选定的 TreePath 集合发生更改时,这些侦听器都会得到通知。

 void

addSelectionPath(TreePath path)
          将路径添加到当前的选择中。

 void

addSelectionPaths(TreePath[] paths)
          向当前的选择中添加路径。

 int

getSelectionMode() 
返回当前选择的模式(SINGLE_TREE_SELECTION、CONTIGUOUS_TREE_SELECTION 或 DISCONTIGUOUS_TREE_SELECTION 之一)。

TreePath

getSelectionPath() 
          返回选择中的第一个路径。

 TreePath[]

getSelectionPaths() 
          返回选择中的路径。

 void

clearSelection() 
          清空当前的选择。

 TreePath

getLeadSelectionPath() 
          返回添加的最后一个路径。

 

Swing提供了默认的接口实现——DefaultTreeSelectionModel。

五.JTree

5.1.JTree的构造

通常有两种方式:

(1)         通过构造TreeNode,然后使用TreeNode来构造JTree;

JTree() 
          返回带有示例模型的 JTree。

JTree(TreeModel newModel)
          返回 JTree 的一个实例,它显示根节点 - 使用指定的数据模型创建树。

JTree(TreeNode root)
          返回 JTree,指定的 TreeNode 作为其根,它显示根节点。

JTree(TreeNode root, boolean asksAllowsChildren)
     返回 JTree,指定的 TreeNode 作为其根,它用指定的方式显示根节点,并确定节点是否为叶节点。

比如:

使用无参数的构造函数,然后再使用setRoot()方法设置Root TreeNode;

使用TreeNode构造TreeModel,然后,使用TreeModel构造JTree;

直接使用Root TreeNode 构造Tree。

 

(2)         使用Object[]、Vector、Hashtable直接构造

JTree(Hashtable<?,?> value)
          返回从 Hashtable 创建的 JTree,它不显示根。

JTree(Object[] value)
          返回 JTree,指定数组的每个元素作为不被显示的新根节点的子节点。

JTree(Vector<?> value)
          返回 JTree,指定 Vector 的每个元素作为不被显示的新根节点的子节点。

5.2.JTree的方法

JTree中含有大量方法,尽管很多都属于外观模式的方法——它会委托给它的各种模型来完成真正的操作。

 

很多方法都很有用,如:

  • isRootVisible()
  • setRootVisible(boolean)
  • setShowsRootHandles(boolean) 节点句柄——绘制在根节点左侧的“小钥匙”

还有些属于坐标<———>Tree转换的方法,如:

  • public TreePath getPathForLocation(int x, int y)
  • public int getRowForLocation(int x, int y)
  • public TreePath getClosestPathForLocation(int x, int y)
  • public int getClosestRowForLocation(int x, int y)

Row<———>Tree转换的方法,如:

  • public TreePath getPathForRow(int row)

六.TreeCellRenderer

通过JTable一样,JTree也使用一个接口定义它的单元绘制器,该接口仅有一个方法:

 

 Component

getTreeCellRendererComponent(JTree tree,Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus)
 当前树单元格的值为value。

 

Swing提供了一个缺省的绘制器——DefaultTreeCellRenderer。它继承自JLabel,提供了一系列方法供改变外观,如:

 Font

getFont() 
          获取此组件的字体。

 Icon

getLeafIcon() 
          返回用于表示叶节点的图标。

 Icon

getOpenIcon() 
          返回用于表示扩展的非叶节点的图标。

Icon

getClosedIcon() 
          返回用于表示没有扩展的非叶节点的图标。

 void

setClosedIcon(Icon newIcon)
          设置用于表示没有扩展的非叶节点的图标。

 void

setFont(Font font)
          创建子类,以便将 FontUIResource 映射为 null。

 void

setLeafIcon(Icon newIcon)
          设置用于表示叶节点的图标。

 void

setOpenIcon(Icon newIcon)
          设置用于表示扩展的非叶节点的图标。

 void

setTextNonSelectionColor(Color newColor)
          设置选定节点时绘制文本所使用的颜色。

 void

setTextSelectionColor(Color newColor)

 

我们可以通过这些方法来进行个性设置,也可以扩展该类,实现自己的TreeCellRender。

 

我们记得,DefaultTableCellRenderer提供了一个钩子方法:setValue(),可以格式化数据。遗憾的是,DefaultTreeCellRenderer没有提供这个方法。如果想要格式化数据,我们需要extends该Renderer,在返回Renderer Component之前格式化数据——按照“标准”实现的话,业务数据应该存放在UserObject中,所以可以通过UserObject获取数据,再进行格式化。

七.TreeCellEditor

TreeCellEditor接口,扩展了CellEditor,在其上只增加了一个方法:

 Component

getTreeCellEditorComponent(JTree tree,Object value, boolean isSelected, boolean expanded, boolean leaf, int row)
          设置编辑器的初始

 

Swing还提供了一个标准的实现——DefaultCellEditor(它同时还实现了TableCellEditor接口)。它有三种构造方式,使Editor组件成为三者之一:

(1)         JComboBox;

(2)         JCheckBox;

(3)         JTextField。

 

如图所示,为一个ComboBox的DefaultCellEditor实现:

上图看起来不太美观——Editor完全占据了Renderer的地盘,导致节点的图标也被遮住。

 

为解决这个问题,Swing又提供了一个TreeCellEditor实现,即DefaultTreeCellEditor。

 

DefaultTreeCellEditor是个装饰者,它装饰TreeCellEditor的一个实现(通常是DefaultCellEditor),并在内部保留了DefaultTreeCellRenderer的句柄,通过Renderer得到图标,然后,返回一个包含图标和TreeCellEditor组件的容器——这样,在editing时也保留了图标,如下图所示:

 

它的构造函数如下所示:

构造方法摘要

DefaultTreeCellEditor(JTree tree,DefaultTreeCellRenderer renderer)
          使用指定呈现器和默认编辑器,为 JTree 构造一个 DefaultTreeCellEditor 对象。

 

DefaultTreeCellEditor(JTree tree,DefaultTreeCellRenderer renderer, TreeCellEditor editor) 
          使用指定的呈现器和指定的编辑器,为 JTree 构造一个 DefaultTreeCellEditor 对象。

 

 

第一个方法没有指定TreeCellEditor,会给它创建一个包含TestEdit的DefaultTreeCellEditor。

 

作为一个装饰者,它将大部分的请求都交由真正的Editor对象处理,除了isCellEditable()——它使用鼠标三击作为触发Editing的手段。

八.树事件

TreeModel激发TreeModelEvent,包括节点的修改、添加、删除;改变树结构等等;

TreeSelectionModel激发TreeSelectionEvent,包括改变选取路径、清除选取等等;

JTree激发TreeExpansionEvent,对应节点的展开和折叠;

DefaultCellEditor激发ChangeEvent——当编辑停止、取消时激发,由CellEditorListener接口进行监听;

                 【注】:editor激发的ChangeEvent有独特的名字,如TableEditor也是如此。

除此之外,JTree还激发鼠标事件。

8.1 TreeSelectionEvent、Listener

Event方法摘要

 Object

cloneWithSource(Object newSource)
          返回接收方的副本,但带有将成为 newSource 的源。

 TreePath

getNewLeadSelectionPath()
          返回当前前导路径

 TreePath

getOldLeadSelectionPath()
          返回以前是前导路径的路径。

 TreePath

getPath() 
          返回第一个路径。

 TreePath[]

getPaths() 
          返回路径数组——已经添加到该选择中或已从中移除的路径。

     通过isAddedPath()来确定是要添加还是删除。

 boolean

isAddedPath() 
          如果已经将第一个路径元素添加到选择中,则返回 true。

 boolean

isAddedPath(int index)
          如果由 index 标识的路径被添加到选择中,则返回 true。

 boolean

isAddedPath(TreePath path)
          如果 path 标识的路径被添加到选择中,则返回 true。

 

前导路径(lead selection path)——即最后添加到选取的路径。

Listener方法摘要

 void

valueChanged(TreeSelectionEvent e)
          每当选择值发生更改时调用。

8.2 TreeExpansionEvent、Listener

Event方法摘要

 

 TreePath

getPath() 
          返回到达已被扩展/折叠的值的路径。

Listener方法摘要

 

 void

treeCollapsed(TreeExpansionEvent event)
          每当树中的一个项被折叠时调用。

 

 void

treeExpanded(TreeExpansionEvent event)
          每当树中的一个项被扩展时调用。

 

 

除此之外,还有TreeWillExpandListener:

方法摘要

 void

treeWillCollapse(TreeExpansionEvent event)
          每当树中的一个节点将被折叠时调用。

 void

treeWillExpand(TreeExpansionEvent event)
          每当树中的一个节点将被扩展时调用。

 

此时,如果抛出ExpandVetoException异常,就可以否决Expansion事件。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值