软件开发

当前位置:首页 > 软件开发

《Java核心技术高级特性》(第六章)(续)

编辑树和树的路径

在下面的- -个示例程序中,将会看到怎样编辑-棵树。 图6-27显示了用户界面。如果点击Add Sibling" (添加兄弟节点)或“Add Child”(添加子节点)按钮,该程序将向树中添加-一个新节点(带有“New" 标题)。如果你点击"Delete" (删除)按钮,该程序将删除当前选中的节点。

为了实现这种行为,需要弄清楚当前选定的是哪个节点。JTree 类用的是一-种令 人惊讶的方式来标识树中的节点。它并不处理树的节点,而是处理对象路径(称为树路径)。一个树路径从根节点开始,由一-个子节点序列构成,参见图6-28。

新梦想IT职业教育

你可能要怀疑JTree类为什么需要整个路径。它不能只获得- -个 TreeNode,然后不断调用getParent方法吗?实际上,JTree 类一点都不清楚TreeNode接口的情况。该接口从来没有被TreeMode1接口用到过,它只被Defau1tTreeMode1的实现用到了。你完全可以拥有其他的树模型,这些树模型中的节点可能根本就没有实现TreeNode接口。如果你使用的是一个管理其他类型对象的树模型,那么这些对象有可能根本就没有getParent和getChild方法。它们彼此之间当然会有其他某种连接。将其他节点连接起来这是树模型的职责,JTree 类本身并没有节点之间连接属性的任何线索。因此,JTree 类总是需要用完整的路径来工作。

TreePath类管理着-一个 object (不是TreeNode ! )引用序列。有很多JTree的方法都可以返回TreePath对象。当拥有- -个树路径时,通常只需要知道其终端节点,该节点可以通过getLastP athComponent方法得到。例如,如果要查找一棵树中当前选定的节点,可以使用JTree类中的getSelectionPath方法。它将返回一个TreePath对象,根据这个对象就可以检索实际节点。

TreePath selectionPath = tree.getSelectionPathO;
DefaultMutableTreeNode selectedNode
= (DefaultMutableTeeNode) selectionPath.getLastPathComponentO;

实际上,由于这种特定查询经常被使用到,因此还提供了一个更方便的方法,它能够立即给出选定的节点。

DefaultutableTreeNode selectedNode
= (fultltabelelode) teetestesecetPathComponentO;

该方法之所以没有被称为getSelectedNode,是因为这棵树并不了解它包含的节点,它的树模型只处理对象的路径。

口注意:树路径是JTree类描述节点的两种方式之一。JTree有许多方法可以接收或返回一个整数索引一 行的位置。行的位置仅仅是节点在树中显示的一个行号(从0开始)。只有那些可视节点才有行号,并且如果一个节点之前的其他节点展开、折叠或者被修改过,这个节点的行号也会随之改变。因此,你应该避免使用行的位置。相反地,所有使用行的JTree方法都有一个与之等价的使用树路径的方法。一旦你选定了的某个节点,那么就可以对它进行编辑了。不过,不能直接向树节点添加子节点:

selectedNode . add(newNode); // No!

如果你改变了节点的结构,那么改变的只是树模型,而相关的视图却没有被通知到。可以自己发送一一个通 知消息,但是如果使用Def aultTreeMode1类的insertNodeInto方法,那么该模型类会全权负责这件事情。例如,下面的调用可以将一-个新节点作为选定节点的最后子节点添加到树中,并通知树的视图。

model .nsertNodentoneMode, selectedNode, sectedNode.getChiIdCountO);

类似的调用removeNodeF romP arent可以移除-个节点并通知树的视图:

model .removeNodeFromParent(selectedNode);

如果想保持节点结构,但是要改变用户对象,那么可以调用下面这个方法:

model .nodeChanged(changedNode);

自动通知是使用DefaultTreeMode1的主要优势。如果你提供自己的树模型,那么必须自己动手实现这种自动通知。(详见Kim Topley撰写的《Core Swing》。)

➊警告: DefaultTreeModel有一个reload方法能够将整个模型重新载入。但是,不要在进行了少数几个修改之后,只是为了更新树而调用reload方法。在重建一棵树的时候,根节点的子节点之后的所有节点将全部再次折叠起来。如果你的用户在每次修改之后都要不断地展开整棵树,这确实是一件令人很不安的事。

当视图接收到节点结构被改变的通知时,它会更新显示树的视图,但是不会自动展开某个节点以展现新添加的子节点。特别是在我们上面那个示例程序中,如果用户将-一个新节点添加到其子节点正处于折叠状态的节点上,那么这个新添加的节点就被悄无声息地添加到了一个处于折叠状态的子树中,这就没有给用户提供任何反馈信息以告诉用户已经实施了该命令。在这种情况下,你可能需要特别费劲地展开所有的父节点,以便让新添加的节点成为可视节点。可以使用类JTree中的方法makeVisible实现这个目的。makeVisible 方法将接受一个树路径作为参数,该树路径指向应该变为可视的节点。

因此,你需要构建-一个从根节点到新添加节点的树路径。为了获得-一个这样的树路径,首先要调用DefaultTreeMode1类中的getPathToRoot方法,它返回一个包含了某- -节点到根节点之间所有节点的数组TreeNode[]。可以将这个数组传递给-一个 TreePath构造器。例如,下面展示了怎样将-一个新节点变成可见的:

TreeNodeD nodes = moel.fetPtToRotnenMode);
TreePath path = new TreePath(nodes);
tree.makeVisible(path);

目注意:令人惊奇的是,DefaultTreeMode1 类好像完全忽视了TreePath类,尽管它的职责是与一个JTree通信。JTree 类大量地使用到了树路径,而它从不使用节点对象数组。

但是,现在假设你的树是放在-一个滚动面板里面,在展开树节点之后,新节点仍是不可见的,因为它落在视图之外。为了克服这个问题,请调用

tree. scoPThToTilibl(ath);

而不是调用makeVisible。这个调用将展开路径中的所有节点,并告诉外围的滚动面板将路径末端的节点滚动到视图中(参见图6-29 )。

默认情况下,这些树节点是不可编辑的。不过,如果调用

tree. setEditable(true);

那么,用户就可以编辑某一节点了。 可以先双击该节点,然后编辑字符串,最后按下回车键。双击操作会调用默认单元格编辑器,它实现了DefaultCel1Editor类(参见图6-30)。也可以安装其他- -些单元格编辑器,其过程与表格单元格编辑器中讨论的过程-一样。

新梦想IT职业教育


相关内容

文章评论

表情

共 0 条评论,查看全部
  • 这篇文章还没有收到评论,赶紧来抢沙发吧~