P35 JTree树

系统:Win10
Java:1.8.0_333
IDEA:2020.3.4
Gitee:https://gitee.com/lijinjiang01/JavaSwing

1.概述

JTree:树。将分层数据显示为树状轮廓的组件。
一颗树由若干节点,通过层级关系组成,一个节点由TreeNode实例来表示,节点在树中的位置(路径)由TreePath实例来表示(定位)。
创建树时,首先要创建一个根节点,然后创建第二层节点添加到根节点,继续创建节点添加到其父节点,最终形成由根节点所引领的一棵树,再由 JTree 数组件显示出来。所有拥有子节点的节点可以自由展开或折叠子节点。
TreeNode 是一个接口,创建节点对象时,通常使用已实现该接口的的 DefaultMutableTreeNode 类。

2.节点(DefaultMutableTreeNode)

DefaultMutableTreeNode 表示一个节点,拥有对节点增删改查等操作的丰富方法。DefaultMutableTreeNode 实现了 MutableTreeNode 接口,而 MutableTreeNode 接口继承自 TreeNode 接口。
DefaultMutableTreeNode 构造方法:

/**
 * 参数说明:
 *     userObject: 节点的用户对象(节点显示的名称)
 *     allowsChildren: 是否允许有子节点
 */
DefaultMutableTreeNode()

DefaultMutableTreeNode(Object userObject)

DefaultMutableTreeNode(Object userObject, boolean allowsChildren)

DefaultMutableTreeNode 常用方法:

// 添加一个子节点在末尾
void add(MutableTreeNode newChild);

// 在指定位置插入一个子节点
void insert(MutableTreeNode newChild, int childIndex) 

// 移除子节点
void remove(int childIndex);
void remove(MutableTreeNode aChild);
void removeAllChildren();

// 获取子节点数量
int getChildCount();
// 获取叶子节点的数量
int getLeafCount();

// 获取指定索引位置的子节点
TreeNode getChildAt(int index);
// 获取指定子节点之后的子节点
TreeNode getChildAfter(TreeNode aChild);
// 获取指定子节点之前的子节点
TreeNode getChildBefore(TreeNode aChild);

// 判断某节点是否为此节点的子节点
boolean isNodeChild(TreeNode aNode);

// 获取此节点的父节点,没有父节点则返回 null
TreeNode getParent();

// 判断此节点是否为根节点
boolean isRoot();

// 判断是否为叶节点(没有子节点即为叶节点,则返回 true)
boolean isLeaf();

// 返回此节点上的级数,从根到此节点的距离。如果此节点为根,则返回 0。
int getLevel();

// 返回从根到此节点的路径。该路径中第一个元素是根节点,最后一个元素是此节点。
TreeNode[] getPath();

// 遍历子节点(只包括直接子节点,不包括孙节点)
Enumeration children();
// 按广度优先的顺序遍历以此节点为根的子树(包含此节点下的所有节点)
Enumeration breadthFirstEnumeration();
// 按深度优先的顺序遍历以此节点为根的子树(包含此节点下的所有节点)
Enumeration depthFirstEnumeration();

// 设置节点的用户对象(节点显示的名称)
void setUserObject(Object userObject);
// 获取节点的用户对象(节点显示的名称)
Object getUserObject();

3.路径(TreePath)

TreePath 表示某节点的路径(从根节点到此节点),一般使用方式:

// 一个节点
DefaultMutableTreeNode node = ...;

// 获取节点的路径(从根节点到此节点沿路径的所有节点集)
TreeNode[] pathNodes = node.getPath();

// 使用节点路径集创建树路径
TreePath treePath = new TreePath(pathNodes);

/* 
 * 这里得到的 treePath 表示的是树中的一个路径,可以定位到具体的节点,
 * 从而对该节点进行相关操作(展开/折叠子节点等),详见后面 JTree 的介绍。
 */

/* 树路径的其他常用方法 */

// 获取此树路径上的所有节点,返回数组的元素为节点对象
Object[] paths = treePath.getPath();

// 获取此树路径上的节点数量
int nodeCount = treePath.getPathCount();

// 获取此树路径表示的节点的父节点的树路径
TreePath parentPath = treePath.getParentPath();

// 判断指定树路径是否为此树路径的“子孙”树路径
boolean isDescendant = treePath.isDescendant(TreePath aTreePath);

4.树(JTree)

JTree表示一个树组件,负责把内存中构造的整颗结构树显示出来。因为对于树结构,只需要得到一个根节点,就相当于获取到了整棵树的应用,因此只需要把一颗树的根节点传递给 JTree 便可显示整棵树。
JTree 实例的创建:

// 方式一: 指定一个根节点创建树
JTree tree = JTree(TreeNode root);

// 方式二: 先创建一个树模型(自定义树模型或使用已实现的默认树模型),再用指定树模型创建树
TreeModel treeModel = new DefaultTreeModel(TreeNode root);
JTree tree = JTree(treeModel);

// 方式三: 先创建一个空树,在设置树模型
JTree tree = JTree();
tree.setModel(TreeModel newModel);

JTree 对节点的操作:

// 通过行索引获取指定行的树路径(这里的行表示的是在 JTree 组件
// 内可以直接看到的行,即不包括已折叠的,根节点行索引为 0,如果
// 根节点展开,则根节点的直接第一个子节点行索引为 1)。
TreePath getPathForRow(int row);
// 根据树路径获取指定节点所在行索引
int getRowForPath(TreePath path);

// 根据在 JTree 组件内的坐标获取指定坐标处所在的节点定位,
// 通过监听鼠标点击事件获取到点击坐标,从而可利用此方法实现
// 监听对节点的单击或双击事件。
int getRowForLocation(int x, int y);
TreePath getPathForLocation(int x, int y);

// 展开指定节点(通过可视行索引或树路径定位目标节点)
void expandRow(int row);
void expandPath(TreePath path);

// 折叠指定节点
void collapseRow(int row);
void collapsePath(TreePath path);

// 判断指定节点是否处于展开状态
boolean isExpanded(int row);
boolean isExpanded(TreePath path);

// 设置当前默认选中的节点(可多选)
void setSelectionRow(int row);
void setSelectionRows(int[] rows);
void setSelectionPath(TreePath path);
void setSelectionPaths(TreePath[] paths);

// 获取当前选中的节点
int[] getSelectionRows();
TreePath getSelectionPath();
TreePath[] getSelectionPaths();

// 是否显示根节点(默认显示)
void setRootVisible(boolean rootVisible);

// 是否显示根节点的句柄(默认不显示)
void setShowsRootHandles(boolean newValue);

// 是否允许编辑节点
void setEditable(boolean flag);

JTree 自定义节点样式(字体、图标等):

// 首先,创建一个树节点的渲染器
DefaultTreeCellRenderer render = new DefaultTreeCellRenderer();

// 设置节点 展开 和 折叠 状态显示的图标
render.setOpenIcon(Icon newIcon);
render.setClosedIcon(Icon newIcon);

// 设置叶子节点显示的图标
render.setLeafIcon(Icon newIcon);

// 设置节点字体,以及 选中 和 未选中 时的颜色
render.setFont(Font font);
render.setTextSelectionColor(Color newColor);
render.setTextNonSelectionColor(Color newColor);

// 设置节点 选中 和 未选中 时的背景颜色
render.setBackgroundSelectionColor(Color newColor);
render.setBackgroundNonSelectionColor(Color newColor);

// 最后,设置树组件的节点渲染器
jTree.setCellRenderer(render);

JTree 对节点变化的监听:

JTree tree = new JTree(rootNode);

/*
 * 节点展开/折叠监听器
 */
tree.addTreeExpansionListener(new TreeExpansionListener() {
    @Override
    public void treeExpanded(TreeExpansionEvent event) {
        System.out.println("展开的节点: " + event.getPath());
    }
    @Override
    public void treeCollapsed(TreeExpansionEvent event) {
        System.out.println("折叠的节点: " + event.getPath());
    }
});

/*
 * 节点展开/折叠监听器(比上一个监听器先执行)
 */
tree.addTreeWillExpandListener(new TreeWillExpandListener() {
    @Override
    public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
        System.out.println("展开的节点: " + event.getPath());
    }
    @Override
    public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
        System.out.println("折叠的节点: " + event.getPath());
    }
});

/*
 * 节点被选中的监听器
 */
tree.addTreeSelectionListener(new TreeSelectionListener() {
    @Override
    public void valueChanged(TreeSelectionEvent e) {
        // 获取被选中的相关节点
        TreePath path = e.getPath();
        TreePath[] paths = e.getPaths();
        TreePath newLeadPath = e.getNewLeadSelectionPath();
        TreePath oldLeadPath = e.getOldLeadSelectionPath();
    }
});

// 节点增删改监听器
tree.getModel().addTreeModelListener(new TreeModelListener() {
    @Override
    public void treeNodesChanged(TreeModelEvent e) {
        System.out.println("节点改变: " + e.getTreePath());
    }
    @Override
    public void treeNodesInserted(TreeModelEvent e) {
        System.out.println("节点插入: " + e.getTreePath());
    }
    @Override
    public void treeNodesRemoved(TreeModelEvent e) {
        System.out.println("节点移除: " + e.getTreePath());
    }
    @Override
    public void treeStructureChanged(TreeModelEvent e) {
        System.out.println("结构改变: " + e.getTreePath());
    }
});

5.代码实例

import com.lijinjiang.beautyeye.BeautyEyeLNFHelper;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;

public class Demo01 {
    public static void main(String[] args) {
        try {
            BeautyEyeLNFHelper.frameBorderStyle = BeautyEyeLNFHelper.FrameBorderStyle.generalNoTranslucencyShadow;
            BeautyEyeLNFHelper.launchBeautyEyeLNF();
        } catch (Exception e) {
            e.printStackTrace();
        }
        JFrame frame = new JFrame("Demo01");
        frame.setSize(300, 300);

        JPanel panel = new JPanel(new BorderLayout());

        // 创建根节点
        DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("中国");

        // 创建二级节点
        DefaultMutableTreeNode node01 = new DefaultMutableTreeNode("北京");
        DefaultMutableTreeNode node02 = new DefaultMutableTreeNode("上海");
        DefaultMutableTreeNode node03 = new DefaultMutableTreeNode("广东");
        DefaultMutableTreeNode node04 = new DefaultMutableTreeNode("浙江");

        // 把二级节点作为子节点添加到根节点
        rootNode.add(node01);
        rootNode.add(node02);
        rootNode.add(node03);
        rootNode.add(node04);

        // 创建三级节点
        DefaultMutableTreeNode child01 = new DefaultMutableTreeNode("北京市");

        DefaultMutableTreeNode child02 = new DefaultMutableTreeNode("上海市");

        DefaultMutableTreeNode child03 = new DefaultMutableTreeNode("广州市");
        DefaultMutableTreeNode child04 = new DefaultMutableTreeNode("深圳市");
        DefaultMutableTreeNode child05 = new DefaultMutableTreeNode("佛山市");

        DefaultMutableTreeNode child06 = new DefaultMutableTreeNode("杭州市");
        DefaultMutableTreeNode child07 = new DefaultMutableTreeNode("宁波市");

        // 把三级节点作为子节点添加到相应的二级节点
        node01.add(child01);

        node02.add(child02);

        node03.add(child03);
        node03.add(child04);
        node03.add(child05);

        node04.add(child06);
        node04.add(child07);

        // 使用根节点创建树组件
        JTree tree = new JTree(rootNode);

        // 设置树显示根节点句柄
        tree.setShowsRootHandles(true);

        // 设置树节点可编辑
        tree.setEditable(true);

        // 设置节点选中监听器
        tree.addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent e) {
                System.out.println("当前被选中的节点: " + e.getPath());
            }
        });

        // 创建滚动面板,包裹树(因为树节点展开后可能需要很大的空间来显示,所以需要用一个滚动面板来包裹)
        JScrollPane scrollPane = new JScrollPane(tree);

        // 添加滚动面板到那内容面板
        panel.add(scrollPane, BorderLayout.CENTER);

        // 设置窗口内容面板并显示
        frame.add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

6.效果演示

在这里插入图片描述

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李晋江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值