Java Swing之–JTree应用详解与示例
JTree 垂直显示其数据。树显示的每一行都包含一项数据,称为节点。每个树都有一个根节点,所有节点都从该节点下降。默认情况下,树显示根节点,但您可以做出其他决定。节点可以有子节点,也可以没有子节点。我们将可以具有子节点的节点(无论它们当前是否具有子节点)称为分支节点。不能有子节点的节点是叶节点。
分支节点可以有任意数量的子节点。通常,用户可以通过单击来展开和折叠分支节点,使其子节点可见或不可见。默认情况下,除根节点之外的所有分支节点开始时都处于折叠状态。
一、JTree类
创建树形控件的类,可以灵活选用构造方法实例化构建树。
1.构造方法
构造方法 | 描述 |
---|---|
JTree() | 返回带有示例模型的 JTree |
JTree(Object[] value) | 返回一个 JTree,其中指定数组的每个元素作为未显示的新根节点的子节点。 |
JTree(Hashtable<?,?> value) | 返回从 Hashtable 创建的 JTree,它不显示在 root 中。 |
JTree(Vector<?> value) | 返回一个 JTree,其中指定 Vector 的每个元素作为未显示的新根节点的子节点。 |
JTree(TreeModel newModel) | 返回 JTree 的实例,它显示根节点——树是使用指定的数据模型创建的。 |
JTree(TreeNode root) | 返回一个以指定的TreeNode为根的JTree,显示根节点。 |
JTree(TreeNode root, boolean asksAllowsChildren) | 返回一个以指定TreeNode为根的JTree,显示根节点,并以指定方式判断一个节点是否为叶节点。 |
使用常用构造方法创建树示例。
- JTree(Object[] value)创建树
//1.使用构造方法JTree(Object[] value)创建树
String [] value = {"张三", "李四", "王五", "赵六", "孙七", "周八", "吴九", "郑十"};
JTree tree1 = new JTree(value);
panel.add(tree1);
- 使用构造方法JTree(Vector value)创建树
//2.使用构造方法JTree(Vector value)创建树
Vector value2 = new Vector();
value2.add("张三");
value2.add("李四");
value2.add("王五")
JTree tree2 = new JTree(value2);
- 使用JTree(Hashtable<?,?> value)创建树
Hashtable<String, String> value3 = new Hashtable<String, String>();
value3.put("1", "张三");
value3.put("2", "李四");
value3.put("3", "王五");
JTree tree3 = new JTree(value3);
- 使用JTree(TreeNode root)创建树
//JTree(TreeNode root)创建树,用root作为根节点
DefaultMutableTreeNode root = new DefaultMutableTreeNode("根节点");
DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("节点1");
DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("节点2");
root.add(node1);
root.add(node2);
JTree tree4 = new JTree(root);
- 使用JTree(TreeModel newModel)创建树
//JTree(TreeModel treeModel)创建树
DefaultTreeModel model = new DefaultTreeModel(root);
JTree tree5 = new JTree(model);
- 使用JTree(TreeNode root, boolean asksAllowsChildren)创建树,并设定是否允许有叶节点
//JTree(TreeNode root, boolean asksAllowsChildren)创建树,false表示是叶子节点,true表示是父节点
DefaultMutableTreeNode root2 = new DefaultMutableTreeNode("根节点", true);
DefaultMutableTreeNode node11 = new DefaultMutableTreeNode("节点1", true);
DefaultMutableTreeNode node22 = new DefaultMutableTreeNode("节点2", true);
DefaultMutableTreeNode node33 = new DefaultMutableTreeNode("节点3", false);
root2.add(node11);
node22.add(node33);
root2.add(node22);
JTree tree6 = new JTree(root2, true);
以上构造方法中用到了节点类DefaultMutableTreeNode、模型类DefaultTreeModel,稍后介绍。
2.常用方法
- TreeModel getModel() 返回创建树使用的模型
DefaultTreeModel model1 = (DefaultTreeModel) tree.getModel();//getModel返回TreeModel,需要转化
- TreePath getPathForRow(int row)返回指定行的路径。
// 获取树中第二行的路径信息
TreePath path = tree.getPathForRow(1);
// 显示路径的字符串表示
JOptionPane.showMessageDialog(null,path.toString());
// 显示路径中节点的数量
JOptionPane.showMessageDialog(null,path.getPathCount());
// 获取路径中的所有节点对象
Object[] path1 = path.getPath();
// 遍历每个节点并显示其字符串表示
for(Object o:path1){
JOptionPane.showMessageDialog(null,o.toString());
}
- TreePath getSelectionPath()返回第一个选定节点的路径。在树形组件的选择监听事件处理中应用该方法能获取到第一个选定节点的路径。
tree.addTreeSelectionListener(e -> {
// 获取当前树组件中用户选择的路径
TreePath path = tree.getSelectionPath();
// 将选中的路径分解为一个对象数组,以便逐个处理路径中的每个节点
Object[] path1 = path.getPath();
// 遍历路径中的每个节点,并将其信息显示给用户
for(Object o:path1){
JOptionPane.showMessageDialog(null,o.toString());
}
}
- Rectangle getRowBounds(int row)获取树中指定行的边界矩形,可用于后续的布局调整或绘制
// 获取树中第一行的边界矩形,用于后续的布局调整或绘制
Rectangle rect = tree.getRowBounds(0);
JOptionPane.showMessageDialog(null,rect.toString());//输出矩形字符串表示
- void setRowHeight(int rowHeight)设置树每个单元格(行)的高度(以像素为单位)。
tree.setRowHeight(20);//tree是已创建好的树
- Dimension getPreferredScrollableViewportSize()返回 的首选 JTree 显示大小 。
// 获取树组件在滚动面板中的首选视口尺寸
dim = tree.getPreferredScrollableViewportSize();
- Dimension getPreferredSize()获取树组件的首选尺寸
// 获取树组件的首选尺寸
Dimension dim = tree.getPreferredSize();
- void setComponentPopupMenu(JPopupMenu popup)设置右键弹出式菜单
//为树添加鼠标右键菜单
tree.setComponentPopupMenu(treePopupMenu());//treePopupMenu是JPopupMenu菜单
- void expandPath(TreePath Path())展开指定路径的节点
//tree是已经创建好的树
//获取选中的节点
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
// 扩展树节点路径,确保指定节点可见
tree.expandPath(new TreePath(node.getPath()));
3.事件处理
JTree中通过注册鼠标、树展开或折叠、树节点选择、树展开等监听完成相关事件的处理。示例如下。
- 为节点添加选中监听器,并获取节点文本
tree.addTreeSelectionListener(e -> {
//获取选中的节点
DefaultMutableTreeNode node = (DefaultMutableTreeNode)
tree.getLastSelectedPathComponent();
//获取节点名称
String nodeName = node.getUserObject().toString();
- 为树添加鼠标监听事件,单击节点,显示面板
//为树添加鼠标监听事件,单击节点,显示面板
tree.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
//获取节点名称--用户对象
if(node != null) {
String nodeName = node.getUserObject().toString();
//根据节点名称显示面板
if (nodeName.equals("Orange")) {
panel1.setVisible(true);
panel2.setVisible(false);
panel3.setVisible(false);
} else if (nodeName.equals("Yellow")) {
panel1.setVisible(false);
panel2.setVisible(true);
panel3.setVisible(false);
} else if (nodeName.equals("Green")) {
panel1.setVisible(false);
panel2.setVisible(false);
panel3.setVisible(true);
} else {
panel1.setVisible(false);
panel2.setVisible(false);
panel3.setVisible(false);
}
}
}
});
- 树节点展开与折叠监听事件处理
//3.树节点展开与折叠监听事件处理
tree.addTreeExpansionListener(new TreeExpansionListener() {
@Override
public void treeExpanded(TreeExpansionEvent event) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)
event.getPath().getLastPathComponent()
JOptionPane.showMessageDialog(null, "展开节点"+node.getUserObject().toString());
}
@Override
public void treeCollapsed(TreeExpansionEvent event) {
JOptionPane.showMessageDialog(null, "折叠");
}
});
- 为树形控件添加展开或折叠前的监听器和事件处理
//4.为树形控件添加将要展开或折叠的监听器
tree.addTreeWillExpandListener(new TreeWillExpandListener() {
@Override
public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
//展开前要执行的操作
}
@Override
public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
//折叠前要执行的操作
}
});
二、 DefaultMutableTreeNode类
DefaultMutableTreeNode 可用来构建树形结构的节点,该模型能被 JTree 组件直接展示。在这个树形结构里存在两种节点,分别是可以包含子节点的分支节点,以及没有子节点的叶节点。节点之间的父子关系明确,每个节点可以有零个或多个子节点,但只能有一个父节点(根节点除外,它没有父节点)。
利用创建的DefaultMutableTreeNode节点结构可以创建JTree树形组件。
示例如下。
// 创建根节点
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
// 创建子节点
DefaultMutableTreeNode child1 = new DefaultMutableTreeNode("Child 1");
DefaultMutableTreeNode child2 = new DefaultMutableTreeNode("Child 2");
// 添加子节点到根节点
root.add(child1);
root.add(child2);
// 为子节点添加子节点(即根节点的孙节点)
DefaultMutableTreeNode grandchild = new DefaultMutableTreeNode("Grandchild");
child1.add(grandchild);
// 创建 JTree 把根节点传递给 JTree 构造函数,就能显示整个树形结构。
JTree tree = new JTree(root);
//DefaultMutableTreeNode 提供了一系列用于操作节点的方法:
// 获取父节点
DefaultMutableTreeNode parent = child1.getParent();
// 获取子节点数量
int childCount = root.getChildCount();
// 移除子节点
root.remove(child2);
// 判断是否为叶节点
boolean isLeaf = grandchild.isLeaf();
三、 DefaultTreeModel类
DefaultTreeModel 是 Java Swing 中用于 JTree 的默认树模型实现,它在 JTree 创建中扮演核心角色,负责管理树的结构、节点关系以及处理节点变更事件。
DefaultTreeModel 存储树的节点结构(父子关系),并维护根节点。所有节点必须是 MutableTreeNode 的实现类(通常使用 DefaultMutableTreeNode)。其技术实现路径如下:
①使用DefaultMutableTreeNode类创建根节点和子节点;
②将子节点添加到根节点;
③以根节点为参数创建DefaultTreeModel 树模型;
④创建JTree,将DefaultTreeModel 模型作为参数,实现树与模型关联;
示例如下:
// 创建根节点
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
// 创建子节点
DefaultMutableTreeNode child1 = new DefaultMutableTreeNode("Child 1");
DefaultMutableTreeNode child2 = new DefaultMutableTreeNode("Child 2");
// 添加子节点到根节点
root.add(child1);
root.add(child2);
// 创建树模型,传入根节点
DefaultTreeModel treeModel = new DefaultTreeModel(root);
// 创建 JTree,关联模型
JTree tree = new JTree(treeModel);
DefaultTreeModel 支持动态添加、删除节点,并自动更新视图,示例如下:
// 获取模型
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
// 添加节点
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新增节点");
DefaultMutableTreeNode parent = (DefaultMutableTreeNode)
tree.getLastSelectedPathComponent();//获取新增节点的父节点
if (parent != null) {
model.insertNodeInto(newNode, parent, parent.getChildCount());//插入节点
// 展开父节点
tree.expandPath(new TreePath(parent.getPath()));
}
// 删除节点
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)
tree.getLastSelectedPathComponent();//获取即将删除节点
if (selectedNode != null && !selectedNode.isRoot()) {
model.removeNodeFromParent(selectedNode);
}
// 修改节点内容
selectedNode.setUserObject("Updated Name");
model.nodeChanged(selectedNode); // 通知模型节点已更改
通过为模型添加 TreeModelListener 监听实现节点变化相关事件处理,该监听实现如下所示:
// 获取模型
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
//注册模型监听处理模型结构变化事件,变化类型有:节点内容变更、节点插入、节点删除、树结构变更
model.addTreeModelListener(new TreeModelListener() {
@Override
public void treeNodesChanged(TreeModelEvent e) { /* 节点内容变更 */ }
@Override
public void treeNodesInserted(TreeModelEvent e) { /* 节点插入 */ }
@Override
public void treeNodesRemoved(TreeModelEvent e) { /* 节点删除 */ }
@Override
public void treeStructureChanged(TreeModelEvent e) { /* 树结构变更 */ }
});
当需要动态操作树结构(如增删节点)时,必须使用 DefaultTreeModel提供完整的节点管理和事件通知机制,所有对树结构的修改必须通过 DefaultTreeModel 提供的方法进行,否则视图不会更新。
四、DefaultTreeCellRenderer类
DefaultTreeCellRenderer实例可以使用各种 setter 方法配置树形控件使用的图标和颜色集,轻松更改用于叶节点、展开分支节点或折叠分支节点的默认图标。
通过在渲染器上调用以下一个或多个方法来指定要使用的图标:
-
setLeafIcon (对于叶节点)
-
setOpenIcon (对于展开的分支节点)
-
setClosedIcon (对于折叠的分支节点)
设置图标后,使用树 setCellRenderer 的方法指定 DefaultTreeCellRenderer 绘制其节点。示例如下。
// 创建一个默认的树单元格渲染器实例
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
// 加载并缩放一个图像图标,用于表示树节点的叶子图标
Image icon = new mageIcon("images/leaficon.png").getImage()
.getScaledInstance(20,20,Image.SCALE_SMOOTH);
// 设置树单元格渲染器的叶子图标
renderer.setLeafIcon(new ImageIcon(icon));
// 设置树单元格渲染器的打开节点图标
renderer.setOpenIcon(new ImageIcon("images/openicon.png"));
// 设置树的单元格渲染器
tree.setCellRenderer(renderer);
五、总结
JTree控件的应用涉及多个接口、类,作者水平有限,仅从个人能实现的角度阐述其应用并演示,读者若想详细而全面的认识和应用,还请查阅官方文档。