swing快速入门(四十四)拖动、编辑JTree结点

注释很详细,直接上代码

上一篇

新增内容(源码细节知识点巨多,建议细看)

1.设置JTree可编辑
2.使用JTree关联的数据模型实现节点的增删改
3.鼠标拖动节点事件设计及处理方法
4.手动刷新视图与自动刷新的方法区别
5.自定位节点视图方法

源码 :

package swing41_50;

import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class swing_test_42 {
    JFrame jFrame ;//定义JFrame对象
    JTree tree;//定义JTree对象
    DefaultTreeModel model;//JTree关联的数据模型对象

    //定义几个初始结点
    DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");
    DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode("广东");
    DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode("广西");
    DefaultMutableTreeNode foshan = new DefaultMutableTreeNode("佛山");
    DefaultMutableTreeNode shantou = new DefaultMutableTreeNode("汕头");
    DefaultMutableTreeNode guilin = new DefaultMutableTreeNode("桂林");
    DefaultMutableTreeNode nanning = new DefaultMutableTreeNode("南宁");

    //定义需要被拖动的TreePath
    TreePath movePath;

    //定义按钮
    JButton addSiblingBtn = new JButton("添加兄弟结点");
    JButton addChildBtn = new JButton("添加子结点");
    JButton deleteBtn = new JButton("删除结点");
    JButton editBtn = new JButton("编辑当前结点");

    //初始化操作
    public void init(){

        //通过add()方法建立父子层级关系
        guangdong.add(foshan);
        guangdong.add(shantou);
        guangxi.add(guilin);
        guangxi.add(nanning);
        root.add(guangdong);
        root.add(guangxi);

        jFrame = new JFrame("可编辑结点的树");//创建JFrame对象
        tree = new JTree(root);//创建JTree对象

        //获取JTree关联的数据模型TreeModel对象
        model = (DefaultTreeModel) tree.getModel();

        //设置JTree可编辑(对一个节点三击中可以编辑)
        tree.setEditable(true);

        //创建鼠标事件监听器
        MouseListener mouseListener = new MouseAdapter() {

            //按下鼠标时,获得被拖动的结点路径
            @Override
            public void mousePressed(MouseEvent e) {

                //如果需要唯一确定某个结点,则必须通过TreePath来获取
                //并且我们后面需要判断目标节点为移动节点的祖先节点,这种情况是不能移动的
                TreePath treePath = tree.getPathForLocation(e.getX(), e.getY());//获取当前点击的结点路径

                if (treePath!=null){//如果点击的结点路径存在
                    movePath = treePath;//将当前点击结点的TreePath保存下来
                }
            }

            //松开树表示可以确定即将被拖入到的父结点
            @Override
            public void mouseReleased(MouseEvent e) {

                TreePath treePath = tree.getPathForLocation(e.getX(), e.getY());//获取当前点击的结点路径

                if (treePath!=null && movePath!=null){//如果移动节点路径和目标节点路径都存在

                    //判断目标路径是否是原路径的子代,如果是则目标路径比原路径短,目标节点是原节点的父代(不包括相等的情况)
                    //成立则说明目标结点是被移动结点的子结点,也就无法移动
                    if (movePath.isDescendant(treePath) && movePath!=treePath){
                        //弹出警告框,提示无法移动
                        JOptionPane.showMessageDialog(jFrame,"目标结点是被移动结点的子结点,无法移动!","非法移动",JOptionPane.WARNING_MESSAGE);
                    }

                    //判断目标节点路径和子节点路径是否为同一个节点
                    //如果成立则说明并非相同节点
                    if (movePath!=treePath){
                        //add方法内部,先将该结点从原父结点删除,然后再把该结点添加到新结点中

                        //获取目标节点和被移动节点

                        //获取路径的最后一个结点,即上一次点击(选中)的节点
                        DefaultMutableTreeNode tartParentNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
                        DefaultMutableTreeNode moveNode = (DefaultMutableTreeNode) movePath.getLastPathComponent();

                        tartParentNode.add(moveNode);//添加子结点(将移动节点作为子节点添加到目标节点中)
                        movePath=null;//清空移动节点

                        tree.updateUI();//更新UI
                    }
                }
            }
        };

        //为JTree添加鼠标监听器
        tree.addMouseListener(mouseListener);

        //创建JPanel对象
        JPanel panel = new JPanel();

        addSiblingBtn.addActionListener(e -> {//添加兄弟结点
            //获取选中结点
            DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

            //如果结点为空,则直接返回
            if (selectedNode==null){
                return;
            }

            //获取该选中结点的父结点
            DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selectedNode.getParent();

            //如果父结点为空,则直接返回
            if (parent==null){
                return;
            }

            //创建一个新结点
            DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");

            //获取选中结点在父节点中的索引
            //因为我们需要插在选中节点的前面
            int selectedIndex = parent.getIndex(selectedNode);

            //在选中位置前面插入新结点(如果想要后面则将selectedIndex+1即可)
            model.insertNodeInto(newNode,parent,selectedIndex);

            //----------显示新结点---------------
            // 这里的显示新节点并非是刷新界面,因为model方法会自动刷新
            //而是为了自动滚动以显示新结点

            //获取从根结点到新结点的所有结点
            TreeNode[] pathToRoot = model.getPathToRoot(newNode);

            //使用指定的结点数组创建TreePath
            TreePath treePath = new TreePath(pathToRoot);

            //显示指定的treePath
            //这个方法的作用是JTree 组件会自动滚动以确保指定路径的节点可见(如果树比较长视图显示不下的情况下有效果)
            tree.scrollPathToVisible(treePath);
        });

        //添加兄弟结点
        panel.add(addSiblingBtn);

        addChildBtn.addActionListener(e -> {
            //获取选中结点
            DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

            if (selectedNode==null){//如果结点为空,则直接返回
                return ;
            }

            //创建新结点
            DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");

            //使用TreeModel的方法添加,不需要手动刷新UI
            //model.insertNodeInto(newNode,selectedNode,selectedNode.getChildCount());

            //使用TreeNode的方法添加,需要手动刷新UI
            selectedNode.add(newNode);

            //显示新结点
            TreeNode[] pathToRoot = model.getPathToRoot(newNode);
            TreePath treePath = new TreePath(pathToRoot);
            tree.scrollPathToVisible(treePath);

            //手动刷新UI
            tree.updateUI();

        });

        panel.add(addChildBtn);//添加子结点

        deleteBtn.addActionListener(e -> {

            //获取选中结点
            DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

            //如果结点存在且存在父结点
            //有小伙伴要问了,为什么还要判断有没有父节点,因为根节点不能删,否则会报错
            if (selectedNode!=null && selectedNode.getParent()!=null){
                //删除选中结点
                model.removeNodeFromParent(selectedNode);
            }

        });

        //删除结点
        panel.add(deleteBtn);

        //实现编辑结点的监听器
        editBtn.addActionListener(e -> {

            //获取选中结点的路径
            TreePath selectionPath = tree.getSelectionPath();

            if (selectionPath!=null){//如果选中结点不为空
                //编辑选中结点
                tree.startEditingAtPath(selectionPath);
            }

        });

        panel.add(editBtn);//编辑结点

        jFrame.add(new JScrollPane(tree));//给树添加滚动条
        jFrame.add(panel, BorderLayout.SOUTH);//添加按钮在南侧

        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗口关闭时退出程序
        jFrame.pack();//自动调整窗口大小
        jFrame.setVisible(true);//显示窗口

    }

    public static void main(String[] args) {
        //启动程序
        new swing_test_42().init();
    }
}

演示效果:

在这里插入图片描述

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

代码对我眨眼睛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值