树组件(JTree)
一棵树只能有一个父节点,可以有0个或者多个子节点,默认情况下,每个节点允许有子节点,可以设置为不允许有子节点。
常用构造方法:
public JTree() 创建一个默认的树
public JTree(TreeNode root) 根据根节点创建树
public JTree(TreeModel newModel) 根据指定树模型创建树
常用方法 | 说明 |
---|---|
public boolean isSelectionEmpty() | 查看是否存在被选中的节点,如果选择当前为空,则返回true。 |
public TreeSelectionModel getSelectionModel() | 获得树选项模型,可以用来设置选择模式 |
public int getSelectionCount() | 获得被选中节点的数量 |
public TreePath getSelectionPath() | 获得选中节点中索引值最小的节点的路径 |
public TreePath[] getSelectionPaths() | 返回所有被选中节点的路径。 |
public void setRootVisible(boolean rootVisible) | 确定 TreeModel 的根节点是否可见。 |
public void setShowsRootHandles(boolean newValue) | 设置 showsRootHandles 属性的值,它指定是否应显示节点句柄。 |
public TreeCellRenderer getCellRenderer() | 返回正在呈现每个单元格的当前 TreeCellRenderer。 |
public void setRowHeight(int rowHeight) | 设置每个单元格的高度(以像素为单位)。如果指定的值小于或等于零,则会查询当前单元格渲染器以获取每个行的高度。 |
public void setFont(Font font) | 设置此组件的字体。 |
public void setSelectionPath(TreePath path) | 选择指定路径标识的节点。 |
public boolean isVisible(TreePath path) | 如果当前可查看路径标识的值,则返回 true,这意味着该路径或者是根路径,或者它的所有父路径均被展开。否则,此方法返回 false。简单点说就是是否有将该节点展开显示出来 |
public void makeVisible(TreePath path) | 确保路径标识的节点当前可查看。就是强制展开显示出来 |
public void setModel(TreeModel newModel) | 设置将提供数据的 TreeModel。 |
public void expandPath(TreePath path) | 确保指定路径标识的节点展开,并且可查看。如果路径中的最后一项是叶节点,则无效。(就是展开节点) |
public Object getLastSelectedPathComponent() | 返回所选路径的最后一个路径组件。 |
DefaultMutableTreeNode(树节点)
DefaultMutableTreeNode实现了TreeNode树节点接口,用来创建树的节点。
常用构造方法:
public DefaultMutableTreeNode() 创建一个树节点,没有父节点,没有子节点,但它允许子节点。
public DefaultMutableTreeNode(Object userObject) 创建一个具有指定标签的节点。
public DefaultMutableTreeNode(Object userObject,boolean allowsChildren) 创建一个具有指定标签的节点,并指定是否允许有子节点。
常用方法 | 说明 |
---|---|
public void add(MutableTreeNode newChild) | 为该节点添加子节点 |
public Enumeration preorderEnumeration() | 返回按前序遍历的枚举对象 |
public Enumeration postorderEnumeration() | 返回按后序遍历的枚举对象 |
public Enumeration breadthFirstEnumeration() | 返回以广度优先遍历的枚举对象 |
public Enumeration depthFirstEnumeration() | 返回以深度优先遍历的枚举对象 |
public Enumeration children() | 返回仅包含该节点子节点的枚举对象 |
public int getLevel() | 获得该节点相对于根节点的级别值,如根节点的子节点的级别值为1 |
public int getDepth() | 获得以此节点为根节点的树的深度,如果该节点没有子节点,则深度为0 |
public TreeNode getParent() | 获得该节点的父节点对象 |
public int getChildCount() | 返回此节点的子节点数。 |
public TreeNode getChildAt(int index) | 返回此节点的子节点数组中指定索引处的子节点。 |
public TreeNode getFirstChild() | 返回此节点的第一个子节点。 如果此节点没有子节点,则抛出NoSuchElementException。 |
public int getSiblingCount() | 返回此节点的兄弟节点数。 |
public DefaultMutableTreeNode getNextSibling() | 获得该节点的后一个兄弟节点 |
public DefaultMutableTreeNode getPreviousSibling() | 获得该节点的前一个兄弟节点 |
public TreeNode[] getPath() | 返回从根到达此节点的路径。该路径中最后一个元素是此节点。 |
public boolean isRoot() | 如果此节点是树的根,则返回 true。根是树中父节点为 null 的唯一节点;每棵树只有一个根。 |
public boolean isLeaf() | 如果此节点没有子节点,则返回 true。要区分没有子节点的节点和不能拥有子节点的节点 |
public void setUserObject(Object userObject) | 将此节点的用户对象设置为 userObject 。即修改用户标签 |
public Object getUserObject() | 返回此节点的用户对象。即获得用户标签 |
DefaultTreeModel(树模型)
DefaultTreeModel实现了TreeModel接口。
常用构造方法:
public DefaultTreeModel(TreeNode root) 创建一个采用默认方式判断节点是否为叶子节点的树模型。
public DefaultTreeModel(TreeNode root,boolean asksAllowsChildren) 创建一个采用指定方式判断节点是否为叶子节点的树模型。
注意:判断节点是否为叶子节点有两种方式:1.默认方式:如果节点不存在子节点,则为叶子节点。2.根据节点是否允许有子节点进行判断,只要不允许有子节点就是叶子节点,如果允许有子节点,即使并不包含任何子节点,也不是叶子节点。当asksAllowsChildren为true时,采用第二种判断方式。
常用方法 | 说明 |
---|---|
public void insertNodeInto(MutableTreeNode newChild,MutableTreeNode parent,int index) | 对它进行调用,以便在父节点的子节点中的 index 位置插入 newChild。(添加树节点)。newChild:新添加节点对象;parent:新添加节点所属父节点对象,该对象必须为树模型中的一个节点;index:新添加节点在其父节点中的索引位置,索引值从0开始 |
public void nodeChanged(TreeNode node) | 更改节点在树中的表示方式之后,调用此方法。(修改节点) |
public void removeNodeFromParent(MutableTreeNode node) | 通知它从其父节点中移除节点。 |
代码示例:
public class ExampleFrame_01 extends JFrame {
private static final long serialVersionUID = 1L;
public static void main(String args[]) {
ExampleFrame_01 frame = new ExampleFrame_01();
frame.setVisible(true);
}
public ExampleFrame_01() {
super();
setTitle("简单的树");
setBounds(100, 100, 500, 375);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 创建根节点
DefaultMutableTreeNode root = new DefaultMutableTreeNode("根节点");
// 创建一级节点
DefaultMutableTreeNode nodeFirst = new DefaultMutableTreeNode(
"一级子节点A");
root.add(nodeFirst);// 将一级节点添加到根节点
DefaultMutableTreeNode nodeSecond = new DefaultMutableTreeNode(
"二级子节点", false);// 创建不允许有子节点的二级节点
nodeFirst.add(nodeSecond);// 将二级节点添加到一级节点
root.add(new DefaultMutableTreeNode("一级子节点B"));// 创建一级节点
JTree treeRoot = new JTree(root);// 利用根节点直接创建树
getContentPane().add(treeRoot, BorderLayout.WEST);
// 利用根节点创建树模型,采用默认的判断方式
DefaultTreeModel treeModelDefault = new DefaultTreeModel(root);
// 利用树模型创建树
JTree treeDefault = new JTree(treeModelDefault);
getContentPane().add(treeDefault, BorderLayout.CENTER);
// 利用根节点创建树模型,并采用非默认的判断方式
DefaultTreeModel treeModelPointed = new DefaultTreeModel(root,
true);
JTree treePointed = new JTree(treeModelPointed);// 利用树模型创建树
getContentPane().add(treePointed, BorderLayout.EAST);
}
}
TreeSelectionModel(树选项模型)
通过TreeSelectionModel(树选项模型)接口可以设置树的选择模式
常用方法 | 说明 |
---|---|
void setSelectionMode(int mode) | 设置选择模型,它必须是SINGLE_TREE_SELECTION,CONTIGUOUS_TREE_SELECTION或DISCONTIGUOUS_TREE_SELECTION之一 |
选择模式静态常量:
静态常量 | 常量值 | 说明 |
---|---|---|
SINGLE_TREE_SELECTION | 1 | 只允许选中一个 |
CONTIGUOUS_TREE_SELECTION | 2 | 允许连续选中多个 |
DISCONTIGUOUS_TREE_SELECTION | 4 | 允许任意选中多个,为树的默认模式 |
TreeSelectionListener接口和TreeSelectionEvent
TreeSelectionListener接口:
树组件注册监听器:addTreeSelectionListener(TreeSelectionListener listener )
void valueChanged(TreeSelectionEvent e):当节点被选中或取消时触发
(Tree)e.getSource()为被选中节点的树对象。
TreePath类
TreePath表示树节点的路径。TreePath 是 TreeModel 提供的 Objects 的数组。对数组的元素进行排序,使根始终是数组的第一个元素 (index 为 0)。
常用方法 | 说明 |
---|---|
public Object[] getPath() | 返回此TreePath的元素的有序数组。 第一个元素是根,即以Object数组的形式 返回该路径中所有节点的对象,在数组中的顺序按照从根节点到子节点的顺序。 |
public Object getLastPathComponent() | 返回此路径的最后一个元素。即此路径最后一个节点的对象 |
public TreePath getParentPath() | 返回父母的TreePath 。 返回值为null表示这是根节点。 |
public TreePath pathByAddingChild(Object child) | 获得向路径中添加指定节点后的路径 |
public int getPathCount() | 返回路径中包含节点的数量 |
public Object getPathComponent(int index) | 返回路径中指定索引位置的节点对象 |
遍历树节点
1.前序遍历
2.后序遍历
3.广度优先遍历
4.深度优先遍历
DefaultMutableTreeNode类提供了两组相对的遍历方式:
方法 | 说明 |
---|---|
public Enumeration preorderEnumeration() | 返回按前序遍历的枚举对象 |
public Enumeration postorderEnumeration() | 返回按后序遍历的枚举对象 |
public Enumeration breadthFirstEnumeration() | 返回以广度优先遍历的枚举对象 |
public Enumeration depthFirstEnumeration() | 返回以深度优先遍历的枚举对象 |
public Enumeration children() | 返回仅包含该节点子节点的枚举对象 |
注意:因为后序遍历和深度优先遍历这两种遍历方式的具体方法相同,实际上方法depthFirstEnumeration()只是调用了方法postorderEnumeration()。
Enumeration<?> enumeration; // 按前序遍历所有树节点
enumeration = root.preorderEnumeration();
while (enumeration.hasMoreElements()) {
DefaultMutableTreeNode node;
node = (DefaultMutableTreeNode) enumeration.nextElement();
if (!node.isLeaf()) {// 判断是否为叶子节点
// 创建该节点的路径
TreePath path = new TreePath(node.getPath());
tree.expandPath(path);// 如果不是则展开该节点
}
定制树
1.定制根节点效果:默认情况下显示树的根节点,但是不显示根节点手柄。可通过如下JTree类中的方法设置:
方法 | 说明 |
---|---|
public void setRootVisible(boolean rootVisible) | 确定 TreeModel 的根节点是否可见。 |
public void setShowsRootHandles(boolean newValue) | 设置 showsRootHandles 属性的值,它指定是否应显示节点句柄。 |
2.定制图标:通过DefaultTreeCellRenderer类(为TreeCellRenderer接口的实现类)的对象可以修改节点图标,通过JTree类的public TreeCellRenderer getCellRenderer()(强转)方法获得,如下:
方法 | 说明 |
---|---|
public void setLeafIcon(Icon newIcon) | 设置用于表示叶节点的图标。 |
public void setClosedIcon(Icon newIcon) | 设置用于表示没有扩展的非叶节点的图标。 |
public void setOpenIcon(Icon newIcon) | 设置用于表示扩展的非叶节点的图标。 |
3.定制连接线效果:默认情况下在树节点之间绘制连接线,通过public final void putClientProperty(Object key,Object value)设置连接线的绘制方式。此时要将入口参数key设置为"JTree.lineStyle"。value为None,表示不绘制节点之间的连接线;设置为Horizontal,表示绘制水平分栏线;设置为Angled,表示绘制节点间的连接线,等效于默认设置。
4.默认情况下只有树的根节点是展开的,其他子节点均处于折叠状态。如果希望在初次运行时树的某一节点就处于展开状态,通过public void expandPath(TreePath path)方法实现,需要传入展开节点的路径。
public class ExampleFrame_04 extends JFrame {
private static final long serialVersionUID = 1L;
private JTree tree;
public static void main(String args[]) {
ExampleFrame_04 frame = new ExampleFrame_04();
frame.setVisible(true);
}
public ExampleFrame_04() {
super();
setTitle("定制树");
setBounds(100, 100, 200, 325);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultMutableTreeNode root;
root = new DefaultMutableTreeNode("企业人事管理系统");
DefaultMutableTreeNode nodeFirstA;
nodeFirstA = new DefaultMutableTreeNode("人事管理");
nodeFirstA.add(new DefaultMutableTreeNode("账套管理"));
nodeFirstA.add(new DefaultMutableTreeNode("考勤管理"));
nodeFirstA.add(new DefaultMutableTreeNode("奖惩管理"));
nodeFirstA.add(new DefaultMutableTreeNode("培训管理"));
root.add(nodeFirstA);
DefaultMutableTreeNode nodeFirstB;
nodeFirstB = new DefaultMutableTreeNode("待遇管理");
nodeFirstB.add(new DefaultMutableTreeNode("帐套管理"));
nodeFirstB.add(new DefaultMutableTreeNode("人员设置"));
nodeFirstB.add(new DefaultMutableTreeNode("待遇报表"));
root.add(nodeFirstB);
DefaultMutableTreeNode nodeFirstC;
nodeFirstC = new DefaultMutableTreeNode("系统维护");
nodeFirstC.add(new DefaultMutableTreeNode("企业架构"));
nodeFirstC.add(new DefaultMutableTreeNode("基本资料"));
nodeFirstC.add(new DefaultMutableTreeNode("系统初始化"));
root.add(nodeFirstC);
tree = new JTree(root);
tree.setRootVisible(false);// 不显示树的根节点
tree.setRowHeight(20);// 树节点的行高为20像素
tree.setFont(new Font("宋体", Font.BOLD, 14));// 设置树结点的字体
// 节点间不采用连接线
tree.putClientProperty("JTree.lineStyle", "None");
DefaultTreeCellRenderer treeCellRenderer;// 获得树节点的绘制对象
treeCellRenderer = (DefaultTreeCellRenderer) tree
.getCellRenderer();
treeCellRenderer.setLeafIcon(null);// 设置叶子节点不采用图标
treeCellRenderer.setClosedIcon(null);// 设置节点折叠时不采用图标
treeCellRenderer.setOpenIcon(null);// 设置节点展开时不采用图标
Enumeration<?> enumeration; // 按前序遍历所有树节点
enumeration = root.preorderEnumeration();
while (enumeration.hasMoreElements()) {
DefaultMutableTreeNode node;
node = (DefaultMutableTreeNode) enumeration.nextElement();
if (!node.isLeaf()) {// 判断是否为叶子节点
// 创建该节点的路径
TreePath path = new TreePath(node.getPath());
tree.expandPath(path);// 如果不是则展开该节点
}
}
getContentPane().add(tree, BorderLayout.CENTER);
}
}
维护树模型
1.添加树节点(向树模型中添加新的节点)
2.修改树节点:DefaultTreeModel类中nodeChanged(TreeNode node)方法用来通知树模型某节点已经被修改,如果修改的是节点的用户对象,修改的信息将不会被同步到GUI界面。
3.删除树节点:从树模型中删除指定节点。
方法 | 说明(属于DefaultTreeModel树模型中的方法) |
---|---|
public void insertNodeInto(MutableTreeNode newChild,MutableTreeNode parent,int index) | 对它进行调用,以便在父节点的子节点中的 index 位置插入 newChild。(添加树节点)。newChild:新添加节点对象;parent:新添加节点所属父节点对象,该对象必须为树模型中的一个节点;index:新添加节点在其父节点中的索引位置,索引值从0开始 |
public void nodeChanged(TreeNode node) | 更改节点在树中的表示方式之后,调用此方法。(修改节点)node为修改后的节点对象。 |
public void removeNodeFromParent(MutableTreeNode node) | 通知它从其父节点中移除节点。 |
1.添加节点
addButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(
textField.getText());// 创建欲添加节点
TreePath selectionPath = tree.getSelectionPath();// 获得选中的父节点路径
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) selectionPath.getLastPathComponent();// 获得选中的父节点
treeModel.insertNodeInto(node, parentNode, parentNode
.getChildCount());// 插入节点到所有子节点之后
TreePath path = selectionPath.pathByAddingChild(node);// 获得新添加节点的路径
if (!tree.isVisible(path))
tree.makeVisible(path);// 如果该节点不可见则令其可见
}
});
2.修改节点
updButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// 获得选中的欲修改节点的路径
TreePath selectionPath = tree.getSelectionPath();
DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectionPath
.getLastPathComponent();// 获得选中的欲修改节点
node.setUserObject(textField.getText());// 修改节点的用户标签
treeModel.nodeChanged(node);// 通知树模型该节点已经被修改
tree.setSelectionPath(selectionPath);// 选中被修改的节点
}
});
3.删除节点
delButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree
.getLastSelectedPathComponent();// 获得选中的欲删除节点
// 查看欲删除的节点是否为根节点,根节点不允许删除
if (!node.isRoot()) {
DefaultMutableTreeNode nextSelectedNode = node
.getNextSibling();// 获得下一个兄弟节点,以备选中
if (nextSelectedNode == null)// 查看是否存在兄弟节点
nextSelectedNode = (DefaultMutableTreeNode) node
.getParent();// 如果不存在则选中其父节点
treeModel.removeNodeFromParent(node);// 删除节点
tree.setSelectionPath(new TreePath(nextSelectedNode
.getPath()));// 选中节点
}
}
});
处理展开节点事件
1.TreeWillExpandListener接口和TreeExpansionEvent
2.TreeExpansionListener接口和TreeExpansionEvent
监听接口 | 事件名称 | 描述 |
---|---|---|
TreeWillExpandListener | TreeExpansionEvent | 当展开和折叠树节点时,将发出TreeExpansionEvent事件,通过实现TreeWillExpandListener接口可以在树节点展开和折叠之前捕获该事件。 |
TreeExpansionListener | TreeExpansionEvent | 通过实现TreeExpansionListener接口可以在树节点展开和折叠时捕获该事件 |
监听接口方法及说明:
1.TreeWillExpandListener接口:
可用于需要验证用户权限,如果用户没有权限查看该节点包含的子节点,则不允许树节点展开。
方法 | 触发 |
---|---|
void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException | 每当树中的一个节点将被扩展时调用。 |
void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException | 每当树中的一个节点将被折叠时调用。 |
2.TreeExpansionListener接口:
方法 | 触发 |
---|---|
void treeExpanded(TreeExpansionEvent event) | 每当树中的一个项被扩展时调用。 |
void treeCollapsed(TreeExpansionEvent event) | 每当树中的一个项被折叠时调用。 |
3.TreeExpansionEvent
常用方法 | 说明 |
---|---|
public TreePath getPath() | 返回到达已被扩展/折叠的值的路径。 |
示例如下:
tree.addTreeWillExpandListener(new TreeWillExpandListener() {
// 树节点将要被折叠时触发
public void treeWillCollapse(TreeExpansionEvent e) {
TreePath path = e.getPath();// 获得将要被折叠节点的路径
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path
.getLastPathComponent();// 获得将要被折叠的节点
System.out.println("节点“" + node + "”将要被折叠!");
}
// 树节点将要被展开时触发
public void treeWillExpand(TreeExpansionEvent e) {
TreePath path = e.getPath();// 获得将要被展开节点的路径
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path
.getLastPathComponent();// 获得将要被展开的节点
System.out.println("节点“" + node + "”将要被展开!");
}
});
// 捕获树节点已经被展开或折叠的事件
tree.addTreeExpansionListener(new TreeExpansionListener() {
// 树节点已经折叠时触发
public void treeCollapsed(TreeExpansionEvent e) {
TreePath path = e.getPath();// 获得已经被折叠节点的路径
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path
.getLastPathComponent();// 获得已经被折叠的节点
System.out.println("节点“" + node + "”已经被折叠!");
System.out.println();
}
// 树节点已经被展开时触发
public void treeExpanded(TreeExpansionEvent e) {
TreePath path = e.getPath();// 获得已经被展开节点的路径
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path
.getLastPathComponent();// 获得已经被展开的节点
System.out.println("节点“" + node + "”已经被展开!");
System.out.println();
}
});