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

这篇具有很好参考价值的文章主要介绍了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();
    }
}

演示效果:

swing快速入门(四十四)拖动、编辑JTree结点,# Swing,swing,java文章来源地址https://www.toymoban.com/news/detail-803571.html

到了这里,关于swing快速入门(四十四)拖动、编辑JTree结点的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • LVS集群 (四十四)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、集群概述 1. 负载均衡技术类型  2. 负载均衡实现方式 二、LVS结构 三、LVS工作模式 四、LVS负载均衡算法  1.  静态负载均衡   2.  动态负载均衡 五、ipvsadm命令详解 六、LVS配置案例 1.  基

    2024年02月11日
    浏览(34)
  • RabbitMQ面试题(四十四道)

    0什么是消息队列: 消息队列的优点: (1)解耦:将系统按照不同的业务功能拆分出来,消息生产者只管把消息发布到 MQ 中而不用管谁来取,消息消费者只管从 MQ 中取消息而不管是谁发布的。消息生产者和消费者都不知道对方的存在; (2)异步:主流程只需要完成业务的

    2024年03月13日
    浏览(27)
  • 【Unity】 HTFramework框架(四十四)【进阶篇】指令系统

    更新日期:2023年5月29日。 Github源码:[点我获取源码] Gitee源码:[点我获取源码] 指令系统 为Unity动态修补程序、热更新等提供了另一种补充方案,我们可以将任意一段 指令代码 即时编译并执行(请放心,即时编译的性能开销极低),达到运行时随意修改程序功能的骚操作。

    2024年02月09日
    浏览(33)
  • Android 项目必备(四十四)-->Android 实现悬浮窗

    悬浮窗是一种比较常见的需求。例如把视频通话界面缩小成一个悬浮窗,然后用户可以在其他界面上处理事情。 本文将讲解悬浮窗实现步骤、原理、实例代码等 1. WindowMananger 接口 Android 的界面绘制,都是通过 WindowMananger 的服务来实现的。那么,既然要实现一个能够在自身应

    2024年02月12日
    浏览(27)
  • leetcode解题思路分析(一百四十四)1247 - 1253 题

    交换字符使得字符串相同 有两个长度相同的字符串 s1 和 s2,且它们其中 只含有 字符 “x” 和 “y”,你需要通过「交换字符」的方式使这两个字符串相同。每次「交换字符」的时候,你都可以在两个字符串中各选一个字符进行交换。交换只能发生在两个不同的字符串之间,

    2024年02月16日
    浏览(32)
  • 第四十四章 Unity 滑动条 (Slider) UI

    本章节我们介绍滑动条 (Slider),它允许用户通过拖动鼠标从预定范围中选择数值。首先,我们点击菜单栏“GameObject”-“UI”-“Slider”,调整其位置,最终效果如下   我们发现滑动条 (Slider)下面有三个子游戏对象Background,Fill Area和Handle Slide Area。他们分别代表了横条背景,以

    2024年02月13日
    浏览(64)
  • Salesforce LWC学习(四十四) Datatable 显示日期类型的有趣点思考

    本篇参考:https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.reference_salesforce_modules 背景: 项目中经常用到datatable显示日期类型字段,并要求日期类型字段基于指定格式显示。这种是一个很常见的需求,而且demo很容易找到,无论是官方文档中还是网上。这里列一个

    2024年02月04日
    浏览(26)
  • 【前端知识】React 基础巩固(四十四)——其他Hooks(useContext、useReducer、useCallback)

    在类组件开发时,我们通过 类名.contextType = MyContext 的方式,在类中获取context,多个Context或者在函数式组件中通过 MyContext.Consumer 方式共享context: 可以看到,当我们需要使用多个Context时,存在大量繁琐的嵌套代码;而Context Hook能够让我们通过Hook直接获取某个Context的值,如

    2024年02月14日
    浏览(37)
  • 【Android从零单排系列四十四】《聊一下Android数据权限permission》

    目录 前言 一.Android 数据权限基本介绍 二 Android 权限分类 三 Android 权限清单 四 Android 动态申请权限DEMO 小伙伴们,在前面的几篇文章中,我们谈到了Android开发中的几种数据存储方式及数据持久化,本文我们介绍下Android开发中的另一部分内容,权限管理。 在Android中,权限管

    2024年02月12日
    浏览(59)
  • SpringBoot系列(四十四):Tomcat与Undertow容器性能对比分析|超级详细,建议收藏

            Tomcat和Undertow都是非常流行的Java Web容器,它们都有自己的优缺点。但在实际项目中,我们如何选择最合适的容器呢?是选择老牌的Tomcat,还是选择后起之秀的Undertow?本篇文章将深入分析Tomcat和Undertow的性能表现,为大家揭秘最佳选择!无论你是Java开发者还是想深

    2023年04月21日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包