The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
With the 使用JTree
class, you can display hierarchical data. JTree
类,可以显示分层数据。A JTree
object does not actually contain your data; it simply provides a view of the data. JTree
对象实际上并不包含您的数据;它只是提供数据的视图。Like any non-trivial Swing component, the tree gets data by querying its data model. 与任何非平凡的Swing组件一样,树通过查询其数据模型来获取数据。Here is a picture of a tree:这是一棵树的图片:
As the preceding figure shows, 如上图所示,JTree
displays its data vertically. JTree
垂直显示其数据。Each row displayed by the tree contains exactly one item of data, which is called a node. 树显示的每一行包含一项数据,称为节点。Every tree has a root node from which all nodes descend. 每棵树都有一个根节点,所有节点都从该根节点下降。By default, the tree displays the root node, but you can decree otherwise. 默认情况下,树显示根节点,但您可以命令其他节点。A node can either have children or not. 节点可以有子节点,也可以没有子节点。We refer to nodes that can have children whether or not they currently have children as branch nodes. 我们指的是可以具有子节点的节点;他们当前是否有子节点作为分支节点。Nodes that can not have children are leaf nodes.不能有子节点的节点是叶节点。
Branch nodes can have any number of children. 分支节点可以有任意数量的子节点。Typically, the user can expand and collapse branch nodes making their children visible or invisible by clicking them. 通常,用户可以扩展和折叠分支节点;使他们的孩子可见或不可见;通过点击它们。By default, all branch nodes except the root node start out collapsed. 默认情况下,除根节点外的所有分支节点开始折叠。A program can detect changes in branch nodes' expansion state by listening for tree expansion or tree-will-expand events, as described in How to Write a Tree Expansion Listener and How to Write a Tree-Will-Expand Listener.程序可以通过侦听树扩展或树将扩展事件来检测分支节点扩展状态的变化,如如何编写树扩展侦听器和如何编写树将扩展侦听器中所述。
A specific node in a tree can be identified either by a TreePath, an object that encapsulates a node and all of its ancestors, or by its display row, where each row in the display area displays one node.树中的特定节点可以通过树路径(封装节点及其所有祖先的对象)或其显示行来标识,其中显示区域中的每一行显示一个节点。
The rest of this section discusses the following topics:本节其余部分讨论以下主题:
Here is a picture of an application, the top half of which displays a tree in a scroll pane.这是一个应用程序的图片,它的上半部分在滚动窗格中显示一个树。
The following code, taken from 以下代码取自TreeDemo.java
, creates the JTree
object and puts it in a scroll pane:TreeDemo.java
,创建JTree
对象并将其放在滚动窗格中:
//Where instance variables are declared: private JTree tree; ... public TreeDemo() { ... DefaultMutableTreeNode top = new DefaultMutableTreeNode("The Java Series"); createNodes(top); tree = new JTree(top); ... JScrollPane treeView = new JScrollPane(tree); ... }
The code creates an instance of 代码创建一个DefaultMutableTreeNode
to serve as the root node for the tree. DefaultMutableTreeNode
实例作为树的根节点。It then creates the rest of the nodes in the tree. 然后创建树中的其余节点。After that, it creates the tree, specifying the root node as an argument to the 之后,它创建树,指定根节点作为JTree
constructor. JTree
构造函数的参数。Finally, it puts the tree in a scroll pane, a common tactic because showing the full, expanded tree would otherwise require too much space.最后,它将树放在滚动窗格中,这是一种常见的策略,因为显示完整的展开树需要太多的空间。
Here is the code that creates the nodes under the root node:下面是在根节点下创建节点的代码:
private void createNodes(DefaultMutableTreeNode top) { DefaultMutableTreeNode category = null; DefaultMutableTreeNode book = null; category = new DefaultMutableTreeNode("Books for Java Programmers"); top.add(category); //original Tutorial book = new DefaultMutableTreeNode(new BookInfo ("The Java Tutorial: A Short Course on the Basics", "tutorial.html")); category.add(book); //Tutorial Continued book = new DefaultMutableTreeNode(new BookInfo ("The Java Tutorial Continued: The Rest of the JDK", "tutorialcont.html")); category.add(book); //Swing Tutorial book = new DefaultMutableTreeNode(new BookInfo ("The Swing Tutorial: A Guide to Constructing GUIs", "swingtutorial.html")); category.add(book); //...add more books for programmers... category = new DefaultMutableTreeNode("Books for Java Implementers"); top.add(category); //VM book = new DefaultMutableTreeNode(new BookInfo ("The Java Virtual Machine Specification", "vm.html")); category.add(book); //Language Spec book = new DefaultMutableTreeNode(new BookInfo ("The Java Language Specification", "jls.html")); category.add(book); }
The argument to the DefaultMutableTreeNode
constructor is the user object which is an object that contains or points to the data associated with the tree node. DefaultMutableTreeNode
构造函数的参数是用户对象,该对象包含或指向与树节点关联的数据。The user object can be a string, or it can be a custom object. 用户对象可以是字符串,也可以是自定义对象。If you implement a custom object, you should implement its 如果实现自定义对象,则应实现其toString
method so that it returns the string to be displayed for that node. toString
方法,以便它返回要为该节点显示的字符串。JTree, by default, renders each node using the value returned from toString, so it is important that 默认情况下,JTree使用从toString
returns something meaningful. toString
返回的值呈现每个节点,因此toString
返回一些有意义的内容是很重要的。Sometimes, it is not feasible to override 有时,覆盖toString
; in such a scenario you can override the convertValueToText of JTree to map the object from the model into a string that gets displayed.toString
是不可行的;在这种情况下,可以重写JTree
的convertValueToText
,将对象从模型映射到显示的字符串。
For example, the 例如,前面代码段中使用的BookInfo
class used in the previous code snippet is a custom class that holds two pieces of data: the name of a book, and the URL for an HTML file describing the book. BookInfo
类是一个自定义类,它包含两部分数据:书籍的名称和描述书籍的HTML文件的URL。The 实现toString
method is implemented to return the book name. toString
方法以返回图书名称。Thus, each node associated with a 因此,与BookInfo
object displays a book name.BookInfo
对象关联的每个节点都显示一个图书名称。
To summarize, you can create a tree by invoking the 总之,您可以通过调用JTree
constructor, specifying the class that implements TreeNode as an argument. JTree
构造函数来创建树,并将实现TreeNode的类指定为参数。You should probably put the tree inside a scroll pane, so that the tree would not take up too much space. 您可能应该将树放在滚动窗格中,这样树就不会占用太多空间。You do not have to do anything to make the tree nodes expand and collapse in response to user clicks. 您不必做任何事情来使树节点响应用户单击而展开和折叠。However, you do have to add some code to make the tree respond when the user selects a node by clicking the node, for example.然而,您必须添加一些代码,以便在用户选择节点时使树响应;例如,通过单击节点。
Responding to tree node selections is simple. 响应树节点选择很简单。You implement a tree selection listener and register it on the tree. 实现树选择侦听器并将其注册到树上。The following code shows the selection-related code from the 以下代码显示了TreeDemo
program:TreeDemo
程序中与选择相关的代码:
//Where the tree is initialized: tree.getSelectionModel().setSelectionMode (TreeSelectionModel.SINGLE_TREE_SELECTION); //Listen for when the selection changes. tree.addTreeSelectionListener(this); ... public void valueChanged(TreeSelectionEvent e) { //Returns the last path element of the selection. //This method is useful only when the selection model allows a single selection. DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (node == null) //Nothing is selected. return; Object nodeInfo = node.getUserObject(); if (node.isLeaf()) { BookInfo book = (BookInfo)nodeInfo; displayURL(book.bookURL); } else { displayURL(helpURL); } }
The preceding code performs these tasks:前面的代码执行这些任务:
TreeSelectionModel
for the tree, and then sets it up so that at most one tree node at a time can be selected.TreeSelectionModel
,然后将其设置为一次最多可以选择一个树节点。TreeSelectionListener
interface.TreeSelectionListener
接口的对象。getLastSelectedPathComponent
method.getLastSelectedPathComponent
方法确定选择哪个节点。getUserObject
method to get the data associated with the node.getUserObject
方法获取与节点关联的数据。For more details about handling tree selection events, see How to Write a Tree Selection Listener.有关处理树选择事件的更多详细信息,请参阅如何编写树选择侦听器。
Here is a picture of some tree nodes, as drawn by the Java, Windows, and Mac OS look and feel implementations.下面是一些树节点的图片,如Java、Windows和Mac OS外观实现所示。
![]() |
![]() |
![]() |
Java look and feel | Windows look and feel | Mac OS look and feel |
As the preceding figures show, a tree conventionally displays an icon and some text for each node. 如上图所示,树通常为每个节点显示一个图标和一些文本。You can customize these, as we will show shortly.您可以自定义这些,我们将很快介绍。
A tree typically also performs some look-and-feel-specific painting to indicate relationships between nodes. 树通常还执行一些特定于外观的绘制,以指示节点之间的关系。You can customize this painting in a limited way. 您可以以有限的方式自定义此绘画。First, you can use 首先,可以使用tree.setRootVisible(true)
to show the root node or tree.setRootVisible(false)
to hide it. tree.setRootVisible(true)
显示根节点,或者使用tree.setRootVisible(false)
隐藏根节点。Second, you can use 其次,您可以使用tree.setShowsRootHandles(true)
to request that a tree's top-level nodes the root node (if it is visible) or its children (if not) have handles that let them be expanded or collapsed.tree.setShowsRootHandles(true)
请求树的顶级节点根节点(如果可见)或其子节点(如果不可见)具有可使其展开或折叠的句柄。
If you are using the Java look and feel, you can customize whether lines are drawn to show relationships between tree nodes. 如果使用的是Java外观,则可以自定义是否绘制线以显示树节点之间的关系。By default, the Java look and feel draws angled lines between nodes. 默认情况下,Java外观在节点之间绘制斜线。By setting the 通过设置树的JTree.lineStyle
client property of a tree, you can specify a different convention. JTree.lineStyle
客户端属性,可以指定不同的约定。For example, to request that the Java look and feel use only horizontal lines to group nodes, use the following code:例如,要请求Java外观仅使用水平线来分组节点,请使用以下代码:
tree.putClientProperty("JTree.lineStyle", "Horizontal");
To specify that the Java look and feel should draw no lines, use this code:要指定Java外观不应绘制线条,请使用以下代码:
tree.putClientProperty("JTree.lineStyle", "None");
The following snapshots show the results of setting the 以下快照显示了使用Java外观时设置JTree.lineStyle
property, when using the Java look and feel.JTree.lineStyle
属性的结果。
![]() |
![]() |
![]() |
"Angled" (default) |
"Horizontal" |
"None" |
No matter what the look and feel, the default icon displayed by a node is determined by whether the node is a leaf and, if not, whether it is expanded. 无论外观如何,节点显示的默认图标都取决于节点是否为叶,如果不是,则取决于是否展开。For example, in the Windows and Motif look and feel implementations, the default icon for each leaf node is a dot; in the Java look and feel, the default leaf icon is a paper-like symbol. 例如,在Windows和Motif外观实现中,每个叶节点的默认图标是点;在Java外观中,默认的叶图标是一个纸质符号。In all the look-and-feel implementations we have shown, branch nodes are marked with folder-like symbols. 在我们展示的所有外观实现中,分支节点都用类似文件夹的符号标记。Some look and feels might have different icons for expanded branches versus collapsed branches.有些外观和感觉对于展开的分支和折叠的分支可能有不同的图标。
You can easily change the default icon used for leaf, expanded branch, or collapsed branch nodes. 可以轻松更改用于叶节点、展开分支节点或折叠分支节点的默认图标。To do so, you first create an instance of 为此,首先创建DefaultTreeCellRenderer
. DefaultTreeCellRenderer
的实例。You could always create your own TreeCellRenderer implementation from scratch, reusing whatever components you like. 您总是可以从头开始创建自己的TreeCellRenderer实现,重用任何您喜欢的组件。Next, specify the icons to use by invoking one or more of the following methods on the renderer: 接下来,通过调用渲染器上的以下一个或多个方法来指定要使用的图标:setLeafIcon
(for leaf nodes), setOpenIcon
(for expanded branch nodes), setClosedIcon
(for collapsed branch nodes). setLeafIcon
(用于叶节点)、setOpenIcon
(用于展开的分支节点)和setClosedIcon
(对于折叠的分支节点)。If you want the tree to display no icon for a type of node, then specify 如果希望树不显示某一类型节点的图标,请为该图标指定null
for the icon. null
。Once you have set up the icons, use the tree's 设置图标后,使用树setCellRenderer
method to specify that the DefaultTreeCellRenderer
paint its nodes. 的setCellRenderer
方法指定DefaultTreeCellRenderer
绘制其节点。Here is an example, taken from 下面是一个来自TreeIconDemo.java
:TreeIconDemo.java
的示例:
ImageIcon leafIcon = createImageIcon("images/middle.gif"); if (leafIcon != null) { DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); renderer.setLeafIcon(leafIcon); tree.setCellRenderer(renderer); }
Here is the screenshot of TreeIconDemo:以下是TreeIconDemo的截图:
If you want finer control over the node icons or you want to provide tool tips, you can do so by creating a subclass of 如果您希望更好地控制节点图标或提供工具提示,可以通过创建DefaultTreeCellRenderer
and overriding the getTreeCellRendererComponent
method. DefaultTreeCellRenderer
的子类并重写getTreeCellRendererComponent
方法来实现。Because 因为DefaultTreeCellRenderer
is a subclass of JLabel
, you can use any JLabel
method such as setIcon
to customize the DefaultTreeCellRenderer
.DefaultTreeCellRenderer
是JLabel
的子类,所以可以使用任何JLabel
方法;例如setIcon
自定义DefaultTreeCellRenderer
。
The following code, from 下面的代码来自TreeIconDemo2.java
, creates a cell renderer that varies the leaf icon depending on whether the word "Tutorial" is in the node's text data. TreeIconDemo2.java
,创建了一个单元格渲染器,根据节点文本数据中是否有“教程”一词来改变叶图标。The renderer also specifies tool-tip text, as the bold lines show. 渲染器还指定工具提示文本,如粗体线所示。
//...where the tree is initialized: //Enable tool tips. ToolTipManager.sharedInstance().registerComponent(tree); ImageIcon tutorialIcon = createImageIcon("images/middle.gif"); if (tutorialIcon != null) { tree.setCellRenderer(new MyRenderer(tutorialIcon)); } ... class MyRenderer extends DefaultTreeCellRenderer { Icon tutorialIcon; public MyRenderer(Icon icon) { tutorialIcon = icon; } public Component getTreeCellRendererComponent( JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { super.getTreeCellRendererComponent( tree, value, sel, expanded, leaf, row, hasFocus); if (leaf && isTutorialBook(value)) { setIcon(tutorialIcon); setToolTipText("This book is in the Tutorial series."); } else { setToolTipText(null); //no tool tip } return this; } protected boolean isTutorialBook(Object value) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; BookInfo nodeInfo = (BookInfo)(node.getUserObject()); String title = nodeInfo.bookName; if (title.indexOf("Tutorial") >= 0) { return true; } return false; } }
Here is the result:结果如下:
You might be wondering how a cell renderer works. 您可能想知道单元格渲染器是如何工作的。When a tree paints each node, neither the 当树绘制每个节点时,JTree
nor its look-and-feel-specific implementation actually contains the code that paints the node. JTree
及其特定于外观的实现实际上都不包含绘制节点的代码。Instead, the tree uses the cell renderer's painting code to paint the node. 相反,树使用单元渲染器的绘制代码绘制节点。For example, to paint a leaf node that has the string "The Java Programming Language", the tree asks its cell renderer to return a component that can paint a leaf node with that string. 例如,要绘制具有字符串“Java编程语言”的叶节点,树要求其单元渲染器返回一个可以使用该字符串绘制叶节点的组件。If the cell renderer is a 如果单元格渲染器是DefaultTreeCellRenderer
, then it returns a label that paints the default leaf icon followed by the string.DefaultTreeCellRenderer
,则它返回一个标签,该标签绘制默认叶图标,后跟字符串。
A cell renderer only paints; it cannot handle events. 单元格渲染器仅绘制;它无法处理事件。If you want to add event handling to a tree, you need to register your handler on either the tree or, if the handling occurs only when a node is selected, the tree's cell editor. 如果要将事件处理添加到树,则需要在树上注册处理程序,或者,如果处理仅在选择节点时发生,则需要注册树的单元格编辑器。For information about cell editors, see Concepts: Editors and Renderers. 有关单元编辑器的信息,请参阅概念:编辑器和渲染器。That section discusses table cell editors and renderers, which are similar to tree cell editors and renderers.本节讨论表单元编辑器和渲染器,它们类似于树单元编辑器和呈现器。
The following figure shows an application called DynamicTreeDemo that lets you add nodes to and remove nodes from a visible tree. 下图显示了一个名为DynamicReedemo的应用程序,该应用程序允许您向可见树添加节点和从可见树中删除节点。You can also edit the text in each node.还可以编辑每个节点中的文本。
The application is based on an example provided by tutorial reader Richard Stanford. 该应用程序基于教程读者Richard Stanford提供的示例。
Here is the code that initializes the tree:下面是初始化树的代码:
rootNode = new DefaultMutableTreeNode("Root Node"); treeModel = new DefaultTreeModel(rootNode); treeModel.addTreeModelListener(new MyTreeModelListener()); tree = new JTree(treeModel); tree.setEditable(true); tree.getSelectionModel().setSelectionMode (TreeSelectionModel.SINGLE_TREE_SELECTION); tree.setShowsRootHandles(true);
By explicitly creating the tree's model, the code guarantees that the tree's model is an instance of 通过显式创建树的模型,代码保证树的模型是DefaultTreeModel
. DefaultTreeModel
的实例。That way, we know all the methods that the tree model supports. 这样,我们就知道树模型支持的所有方法。For example, we know that we can invoke the model's 例如,我们知道我们可以调用模型的insertNodeInto
method, even though that method is not required by the TreeModel
interface.insertNodeInto
方法,即使TreeModel
接口不需要该方法。
To make the text in the tree's nodes editable, we invoke 为了使树节点中的文本可编辑,我们在树上调用setEditable(true)
on the tree. setEditable(true)
。When the user has finished editing a node, the model generates a tree model event that tells any listeners including the 当用户完成编辑节点时,模型生成树模型事件,该事件告诉任何监听器;包括JTree
that tree nodes have changed. JTree
树节点已更改。Note that although 请注意,尽管DefaultMutableTreeNode
has methods for changing a node's content, changes should go through the DefaultTreeModel
cover methods. DefaultMutableTreeNode
具有更改节点内容的方法,但更改应通过DefaultTreeModel
覆盖方法进行。Otherwise, the tree model events would not be generated, and listeners such as the tree would not know about the updates.否则,将不会生成树模型事件,树之类的侦听器将不知道更新。
To be notified of node changes, we can implement a 为了通知节点更改,我们可以实现TreeModelListener
. TreeModelListener
。Here is an example of a tree model listener that detects when the user has typed in a new name for a tree node:下面是一个树模型侦听器的示例,用于检测用户何时为树节点键入了新名称:
class MyTreeModelListener implements TreeModelListener { public void treeNodesChanged(TreeModelEvent e) { DefaultMutableTreeNode node; node = (DefaultMutableTreeNode) (e.getTreePath().getLastPathComponent()); /* * If the event lists children, then the changed * node is the child of the node we have already * gotten. Otherwise, the changed node and the * specified node are the same. */ try { int index = e.getChildIndices()[0]; node = (DefaultMutableTreeNode) (node.getChildAt(index)); } catch (NullPointerException exc) {} System.out.println("The user has finished editing the node."); System.out.println("New value: " + node.getUserObject()); } public void treeNodesInserted(TreeModelEvent e) { } public void treeNodesRemoved(TreeModelEvent e) { } public void treeStructureChanged(TreeModelEvent e) { } }
Here is the code that the Add button's event handler uses to add a new node to the tree:下面是添加按钮的事件处理程序用于将新节点添加到树中的代码:
treePanel.addObject("New Node " + newNodeSuffix++); ... public DefaultMutableTreeNode addObject(Object child) { DefaultMutableTreeNode parentNode = null; TreePath parentPath = tree.getSelectionPath(); if (parentPath == null) { //There is no selection. Default to the root node. parentNode = rootNode; } else { parentNode = (DefaultMutableTreeNode) (parentPath.getLastPathComponent()); } return addObject(parentNode, child, true); } ... public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent, Object child, boolean shouldBeVisible) { DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(child); ... treeModel.insertNodeInto(childNode, parent, parent.getChildCount()); //Make sure the user can see the lovely new node. if (shouldBeVisible) { tree.scrollPathToVisible(new TreePath(childNode.getPath())); } return childNode; }
The code creates a node, inserts it into the tree model, and then, if appropriate, requests that the nodes above it be expanded and the tree scrolled so that the new node is visible. 代码创建一个节点,将其插入到树模型中,然后在适当的情况下,请求展开上面的节点并滚动树,以便新节点可见。To insert the node into the model, the code uses the 要将节点插入模型中,代码使用insertNodeInto
method provided by the DefaultTreeModel
class.DefaultTreeModel
类提供的insertNodeInto
方法。
If 如果DefaultTreeModel
does not suit your needs, then you will need to write a custom data model. DefaultTreeModel
不适合您的需要,则需要编写自定义数据模型。Your data model must implement the 数据模型必须实现TreeModel
interface. TreeModel
接口。TreeModel
specifies methods for getting a particular node of the tree, getting the number of children of a particular node, determining whether a node is a leaf, notifying the model of a change in the tree, and adding and removing tree model listeners.指定用于获取树的特定节点、获取特定节点的子节点数、确定节点是否为叶、通知模型树中的更改以及添加和删除树模型侦听器的方法。
Interestingly, the 有趣的是,TreeModel
interface accepts any kind of object as a tree node. TreeModel
接口接受任何类型的对象作为树节点。It does not require that nodes be represented by 它不要求节点由DefaultMutableTreeNode
objects, or even that nodes implement the TreeNode
interface. DefaultMutableTreeNode
对象来表示,甚至不要求节点实现TreeNode
接口。Thus, if the 因此,如果TreeNode
interface is not suitable for your tree model, feel free to devise your own representation for tree nodes. TreeNode
接口不适合您的树模型,请随意为树节点设计自己的表示。For example, if you have a pre-existing hierarchical data structure, you do not need to duplicate it or force it into the 例如,如果您有一个预先存在的分层数据结构,则不需要复制它或将其强制到TreeNode
mold. TreeNode
模型中。You just need to implement your tree model so that it uses the information in the existing data structure.您只需要实现树模型,以便它使用现有数据结构中的信息。
The following figure shows an application called GenealogyExample that displays the descendants or ancestors of a particular person. 下图显示了一个名为GenealogyExample的应用程序,它显示了特定人的后代或祖先。(Thanks to tutorial reader Olivier Berlanger for providing this example.) (感谢教程读者Olivier Berlanger提供此示例。)
You can find the custom tree model implementation in 您可以在GenealogyModel.java
. GenealogyModel.java
中找到自定义树模型实现。Because the model is implemented as an 因为模型是作为Object
subclass instead of, say, a subclass of DefaultTreeModel
, it must implement the TreeModel
interface directly. Object
子类而不是DefaultTreeModel
的子类实现的,所以它必须直接实现TreeModel
接口。This requires implementing methods for getting information about nodes, such as which is the root and what are the children of a particular node. 这需要实现获取节点信息的方法,例如哪个节点是根节点,哪个节点是特定节点的子节点。In the case of 在GenealogyModel
, each node is represented by an object of type Person
, a custom class that does not implement TreeNode
.GenealogyModel
情况下,每个节点由Person
类型的对象表示,这是一个不实现TreeNode
的自定义类。
A tree model must also implement methods for adding and removing tree model listeners, and must fire 树模型还必须实现用于添加和删除树模型监听器的方法,并且必须在树的结构或数据更改时向这些监听器激发TreeModelEvent
s to those listeners when the tree's structure or data changes. TreeModeEvents
。For example, when the user instructs GenealogyExample to switch from showing ancestors to showing descendants, the tree model makes the change and then fires an event to inform its listeners (such as the tree component).例如,当用户指示GenealogyExample从显示祖先切换到显示后代时,树模型进行更改,然后触发事件通知其监听器(如树组件)。
Lazy loading is a characteristic of an application when the actual loading and instantiation of a class is delayed until the point just before the instance is actually used.延迟加载是应用程序的一个特征,当类的实际加载和实例化延迟到实例实际使用之前。
Do we gain anything by loading them lazily? 我们通过懒洋洋地加载它们获得了什么吗?Yes, this would definitely add to the performance of an application. 是的,这肯定会提高应用程序的性能。By lazily loading, you can dedicate the memory resources to load and instantiate an object only when it is actually used. 通过延迟加载,您可以将内存资源专用于仅在实际使用时加载和实例化对象。You can also speed up the initial loading time of an application.您还可以加快应用程序的初始加载时间。
One of the ways you can lazily load children of a Tree is by utilizing the TreeWillExpandListener interface. 使用TreeWireExpandListener
接口可以惰性地加载树的子级。For example, you can declare and load root, grandparent and parent of a Tree along with the application as shown in the following code:例如,您可以声明和加载树的根、祖父母和父级以及应用程序,如以下代码所示:
Let us declare the root, grandparent and parent as shown below:让我们声明根、祖父母和父母,如下所示:
class DemoArea extends JScrollPane implements TreeWillExpandListener { ....... ....... private TreeNode createNodes() { DefaultMutableTreeNode root; DefaultMutableTreeNode grandparent; DefaultMutableTreeNode parent; root = new DefaultMutableTreeNode("San Francisco"); grandparent = new DefaultMutableTreeNode("Potrero Hill"); root.add(grandparent); parent = new DefaultMutableTreeNode("Restaurants"); grandparent.add(parent); dummyParent = parent; return root; }
You can load above declared nodes to the tree as shown in the following code:您可以将上述声明的节点加载到树中,如以下代码所示:
TreeNode rootNode = createNodes(); tree = new JTree(rootNode); tree.addTreeExpansionListener(this); tree.addTreeWillExpandListener(this); ....... ....... setViewportView(tree);
Now, you can load children lazily to the application whenever the parent node 现在,只要父节点Restaurants
is visible in the application. Restaurants
在应用程序中可见,就可以将子节点惰性加载到应用程序中。To do this, let us declare two children in a separate method and call that method as shown in the following code:为此,让我们在一个单独的方法中声明两个子对象,并调用该方法,如下代码所示:
private void LoadLazyChildren(){ DefaultMutableTreeNode child; child = new DefaultMutableTreeNode("Thai Barbeque"); dummyParent.add(child); child = new DefaultMutableTreeNode("Goat Hill Pizza"); dummyParent.add(child); textArea.append(" Thai Barbeque and Goat Hill Pizza are loaded lazily"); } ....... ....... public void treeWillExpand(TreeExpansionEvent e) throws ExpandVetoException { saySomething("You are about to expand node ", e); int n = JOptionPane.showOptionDialog( this, willExpandText, willExpandTitle, JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, willExpandOptions, willExpandOptions[1]); LoadLazyChildren(); }
See How to Write a Tree-Will-Expand Listener for a description of Tree-Will-Expand listeners.请参阅如何编写树将展开侦听器以了解树将展开的侦听器的描述。
The tree API is quite extensive. The following tables list just a bit of the API, concentrating on the following categories:树API相当广泛。下表仅列出了API的一部分,集中于以下类别:
For more information about the tree API, see the API documentation for 有关树API的更多信息,请参阅JTree
and for the various classes and interfaces in the tree package. JTree
的API文档以及树包中的各种类和接口。Also refer to The JComponent Class for information on the API 有关JTree
inherits from its superclass.JTree
从其超类继承的API的信息,请参阅JComponent类。
JTree |
|
TreePath |
|
TreeNode MutableTreeNode DefaultMutableTreeNode |
|
TreeModel DefaultTreeModel |
|
TreeCellRenderer DefaultTreeCellRenderer |
|
TreeCellEditor DefaultTreeCellEditor |
|
TreeSelectionModel DefaultTreeSelectionModel |
|
TreeSelectionListener TreeSelectionEvent |
|
TreeModelListener TreeModelEvent |
|
TreeExpansionListener TreeWillExpandListener TreeExpansionEvent |
|
ExpandVetoException |
TreeWillExpandListener can throw to indicate that the impending expansion/collapse should not happen. TreeWireExpandListener 可以抛出的异常,以指示即将发生的扩展/崩溃不应发生。 |
JTree(TreeNode) JTree(TreeNode, boolean) JTree(TreeModel) JTree() JTree(Hashtable) JTree(Object[]) JTree(Vector) |
TreeNode argument specifies the root node, to be managed by the default tree model. TreeNode 参数指定要由默认树模型管理的根节点。TreeModel argument specifies the model that provides the data to the table. TreeModel 参数指定为表提供数据的模型。Hashtable , array of objects, or Vector as an argument, then the argument is treated as a list of nodes under the root node (which is not displayed), and a model and tree nodes are constructed accordingly. Hashtable 、对象数组或Vector 作为参数,则该参数将被视为根节点(未显示)下的节点列表,并相应地构造模型和树节点。
|
void setCellRenderer(TreeCellRenderer) |
|
void setEditable(boolean) void setCellEditor(TreeCellEditor) |
|
void setRootVisible(boolean) |
false ,否则为true 。 |
void setShowsRootHandles(boolean) |
false 。setShowsRootHandles(true) .setShowsRootHandles(true) 。 |
void setDragEnabled(boolean) boolean getDragEnabled() |
dragEnabled property, which must be true to enable drag handling on this component. dragEnabled 属性,该属性必须为true 才能在此组件上启用拖动处理。false 。 |
void addTreeSelectionListener(TreeSelectionListener) |
|
void setSelectionModel(TreeSelectionModel) TreeSelectionModel getSelectionModel() |
setSelectionModel(null) .setSelectionModel(null) 完全关闭节点选择。 |
void setSelectionMode(int) int getSelectionMode() (in TreeSelectionModel ) |
CONTIGUOUS_TREE_SELECTION , DISCONTIGUOUS_TREE_SELECTION , or SINGLE_TREE_SELECTION (all defined in TreeSelectionModel ).CONTIGUOUS_TREE_SELECTION 、DISCONTIGUOUS_TREE_SELECTION 或SINGLE_TREE_SELECTION (均在TreeSelectionModel 中定义)。 |
Object getLastSelectedPathComponent() |
getLastPathComponent on the value returned by tree.getSelectionPath() .tree.getSelectionPath() 返回的值调用getLastPathComponent 。 |
void setSelectionPath(TreePath) TreePath getSelectionPath() |
|
void setSelectionPaths(TreePath[]) TreePath[] getSelectionPaths() |
|
void setSelectionPath(TreePath) TreePath getSelectionPath() |
void addTreeExpansionListener(TreeExpansionListener) void addTreeWillExpandListener(TreeWillExpandListener) |
TreeWillExpandListener can throw a ExpandVetoException .TreeWireExpandListener 可以抛出ExpandVetoException 。 |
void expandPath(TreePath) void collapsePath(TreePath) |
|
void scrollPathToVisible(TreePath) |
|
void makeVisible(TreePath) |
|
void setScrollsOnExpand(boolean) boolean getScrollsOnExpand() |
true 。 |
void setToggleClickCount(int) int getToggleClickCount() |
|
TreePath getNextMatch(String, int, Position.Bias) |
TreePath to the next tree element that begins with the specific prefix.TreePath 返回到以特定前缀开头的下一个树元素。 |
This table lists examples that use 下表列出了使用JTree
and where those examples are described.JTree
的示例以及这些示例的描述位置。
TreeDemo |
||
TreeIconDemo |
||
TreeIconDemo2 |
||
DynamicTreeDemo |
||
GenealogyExample |
||
TreeExpandEventDemo |
||
TreeExpandEventDemo2 |
If you are programming in JavaFX, see Tree View.如果您使用JavaFX编程,请参阅树视图。