swing-JTree测试节点的增删改查

这是一个web版本的树管理示例

在这里插入图片描述

swing使用jTree实现树节点的增/删/改

在这里插入图片描述

实现树功能的起步
  • 了解树结构的组成概念
    节点,枝,根,叶,度,层/深度/高度,双亲/孩子/兄弟等
  • 了解树的展开、收起算法
  • 了解树的路径知识
  • 了解子节点与父节点之间的存在的逻辑关系等等
增删改查的思路
  • 从选择的树节点开始, 获得选择的树对象,可以进行修改和删除操作
  • 从选择的树节点开始,可以加入逻辑判断,是添加节点至父节点作为 不可扩展的叶节点,还是修改当前节点为父节点
拖拽的思路
  • 拖拽节点作为初始节点,目标节点作为终止节点,移动根对象位置,比如从1-1-3 移动至 1-3-1等
查找的思路
  • 递归所有的节点,找到符合搜索条件的节点,算法上的优化,可以融入节点直接特定的某些特征作为筛选
jTree增删改查 示例代码

缕清思路最重要,代码没几行
swing的JTree实现节点增删改查,如果不带图标样式 还是相当简单的,这是上图的示例代码

  • 功能按钮: 用到了枚举的小技巧
  • 左侧树: 了解树结构后,便可以轻松的构建初始树
  • 增加主要方法: DefaultTreeModel ==》insertNodeInto
  • 删除主要方法: DefaultTreeModel ==》removeNodeFromParent
  • 更新主要方法: DefaultTreeModel ==》reload

import cn.hutool.core.util.RandomUtil;
import cn.note.swing.core.ui.theme.ButtonFactory;
import cn.note.swing.core.ui.theme.CoreFlatLaf;
import cn.note.swing.core.ui.theme.PngIconFactory;
import cn.note.swing.core.util.FrameUtil;
import cn.note.swing.core.util.WinUtil;
import cn.note.swing.core.view.AbstractMigView;
import cn.note.swing.core.view.Row;
import com.google.common.base.Enums;
import net.miginfocom.swing.MigLayout;
import org.jdesktop.swingx.JXTree;
import org.jdesktop.swingx.icon.EmptyIcon;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * @description: jTree测试
 */
public class JTreeTest extends AbstractMigView {

    private JXTree tree;
    private DefaultTreeModel defaultTreeModel;

    /**
     * 定义migLayout布局
     *
     * @return migLayout布局
     */
    @Override
    protected MigLayout defineMigLayout() {
        return new MigLayout("insets 0,gapy 0,wrap 1");
    }

    /**
     * 初始化成员对象
     */
    @Override
    protected void init() {
        tree = new JXTree(treeData());
        tree.setCellRenderer(new CustomTreeCellRenderer());
        tree.setLeafIcon(new EmptyIcon());
        tree.setOpenIcon(new EmptyIcon());
        tree.setClosedIcon(new EmptyIcon());
    }

    /**
     * render视图
     */
    @Override
    protected void render() {
        addActionTypeEvents();
        view.add(new JScrollPane(tree), "w 300,h 100%");
    }


    private DefaultMutableTreeNode treeData() {
        DefaultMutableTreeNode treeModel = new DefaultMutableTreeNode("root");
        for (int i = 1; i < 4; i++) {
            DefaultMutableTreeNode secondTree = new DefaultMutableTreeNode("dir-" + i);
            treeModel.add(secondTree);
            for (int j = 1; j < 5; j++) {
                DefaultMutableTreeNode nodeTree = new DefaultMutableTreeNode("node-" + j);
                secondTree.add(nodeTree);
            }
        }
        return treeModel;
    }


    private void addActionTypeEvents() {
        Row row = new Row();
        ActionTypeListener actionTypeListener = new ActionTypeListener();
        for (ActionType actionType : ActionType.values()) {
            JButton btn = actionType.toBtn();
            row.add(btn);
            btn.addActionListener(actionTypeListener);
        }
        view.add(row, "w 100%");
    }

    enum ActionType {
        reset, expand, collapse, rename, delete, createParentNode, createNode;

        public JButton toBtn() {
            return ButtonFactory.primaryButton(this.name());
        }
    }

    private class ActionTypeListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            String command = e.getActionCommand();
            ActionType type = Enums.getIfPresent(ActionType.class, command).orNull();
            defaultTreeModel = (DefaultTreeModel) tree.getModel();
            DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

            switch (type) {
                case reset:
                    tree.setModel(new DefaultTreeModel(treeData()));
                    break;
                case expand:
                    tree.expandAll();
                    break;
                case collapse:
                    tree.collapseAll();
                    break;
                case rename:
                    selectNode.setUserObject("rename" + RandomUtil.randomNumbers(8));
                    defaultTreeModel.reload(selectNode);
                    // 局部刷新
//                    Rectangle r = tree.getUI().getPathBounds(tree, tree.getSelectionPath());
//                    tree.repaint(r);
                    break;
                case delete:
                    defaultTreeModel.removeNodeFromParent(selectNode);
                    break;
                case createParentNode:
                    createTreeNode(true);
                    break;
                case createNode:
                    createTreeNode(false);
                    break;
                default:
                    WinUtil.alert("未知的命令:{}", command);
                    break;
            }


        }

        private void createTreeNode(boolean isParent) {

            String label = "node:";
            Icon icon = PngIconFactory.ICON_EXAMPLE;
            if (isParent) {
                label = "p-node:";
                icon = PngIconFactory.ICON_TOPIC;
            }
            DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
            int childCount = selectNode.getChildCount();

            CategoryNode categoryNode = new CategoryNode();
            categoryNode.setIcon(icon);
            categoryNode.setTitle(label + RandomUtil.randomNumbers(5));
            DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(categoryNode);

            newNode.setAllowsChildren(isParent);

            if (selectNode.getAllowsChildren()) {
                defaultTreeModel.insertNodeInto(newNode, selectNode, childCount);
            } else {
                if (childCount == 0) {
                    DefaultMutableTreeNode pNode = (DefaultMutableTreeNode) selectNode.getParent();
                    int addIndex = pNode.getIndex(selectNode);
                    defaultTreeModel.insertNodeInto(newNode, pNode, addIndex + 1);
                } else {
                    defaultTreeModel.insertNodeInto(newNode, selectNode, childCount);
                }
            }

        }
    }

    public static void main(String[] args) {
        CoreFlatLaf.install();
        FrameUtil.launchTest(JTreeTest.class);
    }
}

这是动态添加图标的render类
public class CustomTreeCellRenderer extends DefaultTreeCellRenderer {


    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value,
                                                  boolean sel, boolean expanded, boolean leaf, int row,
                                                  boolean hasFocus) {

        super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
                row, hasFocus);
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
        Object userObject = node.getUserObject();
        if (userObject instanceof CategoryNode) {
            CategoryNode categoryNode = (CategoryNode) userObject;
            super.setText(categoryNode.getTitle());
            super.setIcon(categoryNode.getIcon());
        }
        return this;

    }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值