JTree、TreeModel实现树
树也是图形用户界面中使用非常广泛的GUI组件,在Windows资源管理器中,将我们所看到的目录称为树:

计算机世界里的树是由一系列具有严格父子关系的结点组成的,每个结点既可以是上一级结点的子结点,也可以是其下一级结点的父结点,因此同一个结点既可以是父结点也可以是子结点。
按照结点是否包含子结点,可以把结点分为下面两类:
普通结点:包含子结点的结点;
叶子结点:没有子结点的结点;
按照结点是否具有唯一的父结点,可以把结点分为下面两类:
根结点:没有父结点的结点,计算机中,一棵树只能有一个根结点
普通结点:具有唯一父结点的结点
创建树:

package com.aynu.layout;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
public class SimpleJTree {
    JFrame jf = new JFrame("简单树");
    public void init() {
        //创建DefaultMutableTreeNode对象来代表结点
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");
        DefaultMutableTreeNode henan = new DefaultMutableTreeNode("河南");
        DefaultMutableTreeNode zhengzhou = new DefaultMutableTreeNode("郑州");
        DefaultMutableTreeNode luoyang = new DefaultMutableTreeNode("洛阳");
        DefaultMutableTreeNode shanxi = new DefaultMutableTreeNode("陕西");
        DefaultMutableTreeNode xian = new DefaultMutableTreeNode("西安");
        DefaultMutableTreeNode baoji = new DefaultMutableTreeNode("宝鸡");
        //组装结点之间的关系
        root.add(henan);
        root.add(shanxi);
        henan.add(zhengzhou);
        henan.add(luoyang);
        shanxi.add(xian);
        shanxi.add(baoji);
        //创建JTree对象
        JTree tree = new JTree(root);
        //把JTree放到窗口中展示
            jf.add(tree);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.pack();
        jf.setVisible(true);
    }
    public static void main(String[] args) {
        new SimpleJTree().init();
    }
}
 

JTree的其他外观设置方法:
tree.putClientProperty("JTree.lineStyle","None"):设置结点之间没有连接线
tree.putClientProperty("JTree.lineStyle","Horizontal"):设置结点之间只要水平分割线

package com.aynu.layout;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
public class SimpleJTree {
    JFrame jf = new JFrame("简单树");
    public void init() {
        //创建DefaultMutableTreeNode对象来代表结点
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");
        DefaultMutableTreeNode henan = new DefaultMutableTreeNode("河南");
        DefaultMutableTreeNode zhengzhou = new DefaultMutableTreeNode("郑州");
        DefaultMutableTreeNode luoyang = new DefaultMutableTreeNode("洛阳");
        DefaultMutableTreeNode shanxi = new DefaultMutableTreeNode("陕西");
        DefaultMutableTreeNode xian = new DefaultMutableTreeNode("西安");
        DefaultMutableTreeNode baoji = new DefaultMutableTreeNode("宝鸡");
        //组装结点之间的关系
        root.add(henan);
        root.add(shanxi);
        henan.add(zhengzhou);
        henan.add(luoyang);
        shanxi.add(xian);
        shanxi.add(baoji);
        //创建JTree对象
        JTree tree = new JTree(root);
        //tree.putClientProperty("JTree.lineStyle","None"):设置结点之间没有连接线
       // tree.putClientProperty("JTree.lineStyle","None");
        //tree.putClientProperty("JTree.lineStyle","Horizontal"):设置结点之间只要水平分割线
       // tree.putClientProperty("JTree.lineStyle","Horizontal");
        //把JTree放到窗口中展示
            jf.add(tree);
        //DefaultMutbleTreeNode getNextSibling:返回此结点的下一个兄弟结点
        DefaultMutableTreeNode nextNode = henan.getNextSibling();
        System.out.println(nextNode);
        //TreeNode getParent():返回此结点的父结点。如果此结点没有父结点则返回null
        TreeNode parent = henan.getParent();
        System.out.println(parent);
        //boolean isLeaf():返回该结点是否是叶子结点
        System.out.println(shanxi.isLeaf());
        System.out.println(xian.isLeaf());
        //boolean isRoot():返回当前结点是否是根结点
        System.out.println(shanxi.isRoot());
        System.out.println(root.isRoot());
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.pack();
        jf.setVisible(true);
    }
    public static void main(String[] args) {
        new SimpleJTree().init();
    }
}
 

编辑树结点:

package com.aynu.layout;
import com.sun.source.tree.Tree;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.tree.*;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class SimpleJTree2 {
    JFrame jf = new JFrame("可编辑结点的树");
    //创建DefaultMutableTreeNode对象来代表结点
    DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");
    DefaultMutableTreeNode henan = new DefaultMutableTreeNode("河南");
    DefaultMutableTreeNode zhengzhou = new DefaultMutableTreeNode("郑州");
    DefaultMutableTreeNode luoyang = new DefaultMutableTreeNode("洛阳");
    DefaultMutableTreeNode shanxi = new DefaultMutableTreeNode("陕西");
    DefaultMutableTreeNode xian = new DefaultMutableTreeNode("西安");
    DefaultMutableTreeNode baoji = new DefaultMutableTreeNode("宝鸡");
    //定义按钮,完成操作
    JButton addSiblingBtn = new JButton("添加兄弟结点");
    JButton addChildBtn = new JButton("添加子结点");
    JButton deleteBtn = new JButton("删除结点");
    JButton editBtn = new JButton("编辑当前结点");
    public void init() {
        //组装结点之间的关系
        root.add(henan);
        root.add(shanxi);
        henan.add(zhengzhou);
        henan.add(luoyang);
        shanxi.add(xian);
        shanxi.add(baoji);
        //创建JTree对象
        JTree tree = new JTree(root);
        //完成树的结点编辑的代码
        tree.setEditable(true);
        DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
        //处理添加按钮
        addSiblingBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //添加兄弟结点逻辑
                //1.获取当前选中的结点
                DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
                if (selectNode == null) {
                    return;
                }
                //2.获取当前结点的父结点
                DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) selectNode.getParent();
                if (parentNode == null) {
                    return;
                }
                //3.创建新结点
                DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");
                //4.把新结点通过父结点进行添加
                int index = parentNode.getIndex(selectNode);
                model.insertNodeInto(newNode,parentNode,index);
                //5.显示新结点
                TreeNode[] pathToRoot = model.getPathToRoot(newNode);
                TreePath treePath = new TreePath(pathToRoot);
                tree.scrollPathToVisible(treePath);
                //6.重绘tree
                tree.updateUI();
            }
        });
        //添加子结点
        addChildBtn.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                //为选中结点添加子结点
                //获取选中结点
                DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
                if (selectNode==null){
                    return;
                }
                //创建新结点
                DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");
                //把新结点添加到当前结点中
                selectNode.add(newNode);
                //显示新结点
                TreeNode[] pathToRoot = model.getPathToRoot(newNode);
                TreePath treePath = new TreePath(pathToRoot);
                tree.scrollPathToVisible(treePath);
                //重绘UI
                tree.updateUI();
            }
        });
        //删除处理
        deleteBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //获取选中结点
                DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
                if (selectNode!=null && selectNode.getParent()!=null){
                    model.removeNodeFromParent(selectNode);
                }
            }
        });
        //处理编辑
        editBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //获取当前选中结点的路径
                TreePath selectionPath = tree.getSelectionPath();
                //判断如果路径不为空,则设置该路径的最后一个结点可编辑
                if (selectionPath!=null){
                    tree.startEditingAtPath(selectionPath);
                }
            }
        });
        //组装视图
        jf.add(new JScrollPane(tree));
        JPanel jPanel =new JPanel();
        jPanel.add(addSiblingBtn);
        jPanel.add(addChildBtn);
        jPanel.add(deleteBtn);
        jPanel.add(editBtn);
        jf.add(jPanel, BorderLayout.SOUTH);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.pack();
        jf.setVisible(true);
    }
    public static void main(String[] args) {
        new SimpleJTree2().init();
    }
}
 

监听结点事件 :
使用DefaultTreeCellRenderer改变结点外观:

结点外观改变_扩展DefaultTreeCellRenderer:

实现TreeCellRenderer接口改变结点外观:
这种改变结点外观的方式是最灵活的,程序实现TreeCellRenderer接口时同样需要实现getTreeCellRendererComponent()方法,该方法可以返回任意类型的组件,该组件将作为Tree的结点,通过这种方法可以最大程度的改变结点的外观。


















