Swing高级--树组件

一、简单的树

先来看看什么是树:

就跟文件目录一样是一级一级的。下面是上图的代码:

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import java.awt.*;

public class jTree extends JFrame {
    public jTree(){
        Container c = getContentPane();
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("根节点");//创建一个具有指定标签的节点
        DefaultMutableTreeNode fi = new DefaultMutableTreeNode("一级子节点A");
        root.add(fi);//将子节点添加到根节点
        DefaultMutableTreeNode two = new DefaultMutableTreeNode("二级子节点",false);//不允许有子节点
        fi.add(two);//将二级子节点添加到一级子节点
        root.add(new DefaultMutableTreeNode("一级子节点B"));
        JTree jt = new JTree(root);//根据root根节点创建树
        c.add(jt,BorderLayout.WEST);
        DefaultTreeModel model = new DefaultTreeModel(root);//根据root根节点创建树模型并判断节点是否是叶子节点(默认方式判断)
        JTree jt2 = new JTree(model);//根据树模型创建树
        c.add(jt2,BorderLayout.CENTER);
        DefaultTreeModel model2 = new DefaultTreeModel(root,true);//根据root根节点并判断节点是否为叶子节点(指定方式判断)
        /**
         * 默认判断是否是叶子节点:如果该节点没有子节点,就为叶子节点。
         *指定方式方式判断是否是叶子节点:节点是否允许有子节点,如果不允许则为叶子节点,如果允许,就算没有子节点也不是叶子节点
         */
        JTree jt3 = new JTree(model2);
        c.add(jt3,BorderLayout.EAST);
        setVisible(true);
        setSize(300,500);
        setDefaultCloseOperation(3);
    }

    public static void main(String[] args) {
        new jTree();
    }
}

二、处理选中节点事件

        树的节点允许为被选中和取消选中状态,通过捕获树节点的选择事件,可以处理相应的操作。树的选择模式有3种,通过TreeSelectionModel类的对象可以设置树的选择模式。可以通过JTree类的getSelectionModel()方法获得TreeSelectionModel类的对象,然后通过TreeSelectionModel类的setSelection(int mode)方法设置选择模式。 

SINGLE_TREE_SELECTION               1        只允许选中一个
CONTIGUOUS_TREE_SELECTION           2        允许连续选中多个
DISCONTIGUOUS_TREE_SELECTION        4        允许任意选中多个,为树的默认模式

        当选中树节点和取消树节点的选中状态时,将发出TreeSelectionEvent事件,通过实现TreeSelectionListener接口可以捕获该事件。TreeSelectionListener接口的具体定义如下:

public interface TreeSelectionListener extends EventListener {
    void valueChanged(TreeSelectionEvent e);
}

        当捕获发出TreeSelectionEvent事件时,void valueChanged(TreeSelectionEvent e)方法将被触发执行,此时通过JTree类的getSelectionPaths()方法可以获得所有被选中节点的路径,该方法将返回一个TreePath类型的数组;通过getSelectionPath()将获得选中节点中索引值最小的节点的路径(TreePath类的对象),也可以理解为选中节点中离根节点最近的节点的路径。在获得选中节点的路径之前,可以通过JTree类的isSelectionEmpty()方法查看是否存在被选中的节点,如果返回false,表示存在,通过getSelectionCount()方法可以获得被选中节点的数量。

TreePath类表示树节点的路径,即通过该类可以获得子节点所属的父节点,以及父节点所属的上级节点,直到数的根节点。TreePath类的常用方法如下:

方法说明
getPath()以Object数组的形式返回该路径中所有节点的对象,在数组中的顺序按照从根节点到子节点的顺序
getLastPathComponent()获得路径中最后一个节点的对象
getParentPath()获得路径中除了最后一个节点的路径
pathByAddingChild(Object child)获得向路径中添加指定节点后的路径
getPathCount()获得路径中包含节点的数量
getPathComponent(int element)获得路径中指定索引位置的节点对象
下面是示例代码:  
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;

public class jTree3 extends JFrame {
    public jTree3(){
        Container c = getContentPane();
        setTitle("处理选中节点事件");
        //创建根节点
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("本地磁盘(D:)");
        //添加子节点
        DefaultMutableTreeNode tu = new DefaultMutableTreeNode("图片");
        root.add(tu);
        root.add(new DefaultMutableTreeNode("音乐"));
        tu.add(new DefaultMutableTreeNode("千山"));
        DefaultMutableTreeNode shan = new DefaultMutableTreeNode("凤凰山");
        tu.add(shan);
        shan.add(new DefaultMutableTreeNode("图1", false));
        shan.add(new DefaultMutableTreeNode("图2", false));
        //根据树模型创建树
        DefaultTreeModel model = new DefaultTreeModel(root,true);
        JTree tree = new JTree(model);
        c.add(tree);
        //获得树的选择模式
        TreeSelectionModel treeSelectionModel = tree.getSelectionModel();
        //设置树的选择模式为连选
        treeSelectionModel.setSelectionMode(TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
        //给树添加监听事件
        tree.addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent e) {
                //判断是否存在选中节点
                if (!tree.isSelectionEmpty()){
                    //获得所有被选中节点的路径
                    TreePath[] paths = tree.getSelectionPaths();
                    for (int i = 0; i < paths.length; i++) {
                        //获得选中节点的路径
                        TreePath path = paths[i];
                        //返回该路径中的所有节点的对象
                        Object[] oPath = path.getPath();
                        for (int j = 0; j < oPath.length; j++) {
                            //获得节点
                            DefaultMutableTreeNode node = (DefaultMutableTreeNode) oPath[j];
                            String s = node.getUserObject()+(j==(oPath.length-1)?"":"-->");
                            System.out.print(s);//输出节点标签
                        }
                        System.out.println();
                    }
                    System.out.println();
                }
            }
        });
        setVisible(true);
        setSize(500,500);
        setDefaultCloseOperation(3);
    }

    public static void main(String[] args) {
        new jTree3();
    }
}

三、遍历树节点

         有时候需要对树进行遍历,也就是遍历树中的部分或全部节点,以便查找某一节点,或者是对树中的结点执行某一操作。DefaultMutableTreeNode类提供了两组相对的遍历方式:前序遍历和后序遍历,广度优先遍历和深度优先遍历。

        通过DefaultMutableTreeNode类的childrem()方法,可以得到仅包含该节点子节点的枚举对象,以便快速遍历节点的子节点。在DefaultMutableTreeNode类中还提供了一些常用方法,如下

getLevel()//获得该节点相对于根节点的级别值,如根节点的子节点的级别值为1
getDepth()//获得以此节点为根节点的树的深度,如果该节点没有子节点,则深度为0
getParent()//获得该节点的父节点对象
getChildCount()//获得该节点拥有字节点的个数
getFirstChild()//获得该节点的第一个子节点对象
getSiblingCount()//获得该节点拥有的兄弟节点的个数
getNextSibling()//获得该节点的后一个兄弟节点
getPreviousSibling()//获得该节点的前一个兄弟节点
getPath()//获得该节点的路径
isRoot()//判断该节点是否为根节点
isLeaf()//判断该节点是否为叶子节点

 下面是通过按钮控选择遍历方式的示例代码:

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

public class  jTree2 extends JFrame {

    private static final long serialVersionUID = 1L;
    private DefaultMutableTreeNode root;

    public static void main(String args[]) {
        jTree2 frame = new jTree2();
        frame.setVisible(true);
    }

    public jTree2() {
        super();
        setTitle("遍历树节点");
        setBounds(100, 100, 290, 260);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //创建根节点
        root = new DefaultMutableTreeNode("ROOT");
        //创建一级节点
        DefaultMutableTreeNode A = new DefaultMutableTreeNode("A");
        //添加二级节点
        A.add(new DefaultMutableTreeNode("AA"));
        A.add(new DefaultMutableTreeNode("AB"));
        root.add(A);

        DefaultMutableTreeNode B = new DefaultMutableTreeNode("B");
        root.add(B);

        DefaultMutableTreeNode C = new DefaultMutableTreeNode("C");
        C.add(new DefaultMutableTreeNode("CA"));
        DefaultMutableTreeNode CB = new DefaultMutableTreeNode("CB");
        CB.add(new DefaultMutableTreeNode("CBA"));
        CB.add(new DefaultMutableTreeNode("CBB"));
        C.add(CB);
        C.add(new DefaultMutableTreeNode("CC"));
        root.add(C);
        //创建树
        JTree tree = new JTree(root);
        getContentPane().add(tree, BorderLayout.CENTER);

        final JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(0, 1));
        getContentPane().add(panel, BorderLayout.EAST);
        final JButton b1 = new JButton("按前序遍历节点");
        b1.addActionListener(new ButtonActionListener("按前序遍历"));
        panel.add(b1);
        final JButton b2 = new JButton("按后序遍历节点");
        b2.addActionListener(new ButtonActionListener("按后序遍历"));
        panel.add(b2);
        final JButton b3 = new JButton("以广度优先遍历");
        b3.addActionListener(new ButtonActionListener("以广度优先遍历"));
        panel.add(b3);
        final JButton b4 = new JButton("以深度优先遍历");
        b4.addActionListener(new ButtonActionListener("以深度优先遍历"));
        panel.add(b4);
        final JButton b5 = new JButton("遍历直属子节点");
        b5.addActionListener(new ButtonActionListener("遍历子节点"));
        panel.add(b5);
    }

    private class ButtonActionListener implements ActionListener {
        private String mode;
        public ButtonActionListener(String mode) {
            this.mode = mode;
        }
        
        public void actionPerformed(ActionEvent e) {
            Enumeration<?> enumeration;// 声明节点枚举对象
            System.out.println(mode);
            if (mode.equals("按前序遍历"))
                // 按前序遍历所有树节点
                enumeration = root.preorderEnumeration();
            else if (mode.equals("按后序遍历"))
                // 按后序遍历所有树节点
                enumeration = root.postorderEnumeration();
            else if (mode.equals("以广度优先遍历"))
                // 以广度优先遍历所有树节点
                enumeration = root.breadthFirstEnumeration();
            else if (mode.equals("以深度优先遍历"))
                // 以深度优先遍历所有树节点
                enumeration = root.depthFirstEnumeration();
            else
                enumeration = root.children(); // 遍历该节点的子节点
            while (enumeration.hasMoreElements()) {// 遍历节点枚举对象
                DefaultMutableTreeNode node;// 获得节点
                node = (DefaultMutableTreeNode) enumeration.nextElement();
                // 根据节点级别输出占位符
                for (int l = 0; l < node.getLevel(); l++) {
                    System.out.print("----");
                }
                System.out.println(node.getUserObject());// 输出节点标签
            }
            System.out.println();
        }
    }
}

 这样看遍历顺序还是很直观的

 四、定制树

        在使用树时,经常需要对树进行一系列的设置,例如,对节点图标的设置,对节点间连线的设置,以及对树展开情况的设置等,以便实现实际需要的视觉效果。(借用一下最开始的树节点代码)

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.util.Enumeration;

public class jTree extends JFrame {
    public static void main(String[] args) {
        jTree jTree = new jTree();
        jTree.setVisible(true);

    }
    public jTree(){
        super();
        setTitle("定制树");
        setBounds(100, 100, 320, 260);
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("根节点");//创建一个具有指定标签的节点
        DefaultMutableTreeNode fi = new DefaultMutableTreeNode("一级子节点A");
        root.add(fi);//将子节点添加到根节点
        DefaultMutableTreeNode two = new DefaultMutableTreeNode("二级子节点",false);//不允许有子节点
        fi.add(two);//将二级子节点添加到一级子节点
        root.add(new DefaultMutableTreeNode("一级子节点B"));
        JTree jt = new JTree(root);//根据root根节点创建树

        jt.setRootVisible(false);//不显示树的根节点

        jt.setRowHeight(50);//设置树节点的行高为50

        jt.setFont(new Font("宋体", Font.BOLD, 14));//设置树节点的字体


        getContentPane().add(jt,BorderLayout.WEST);
        DefaultTreeModel model = new DefaultTreeModel(root);//根据root根节点创建树模型并判断节点是否是叶子节点(默认方式判断)
        JTree jt2 = new JTree(model);//根据树模型创建树

        jt2.putClientProperty("JTree.lineStyle","None");//设置节点之间没有连线

        getContentPane().add(jt2,BorderLayout.CENTER);
        DefaultTreeModel model2 = new DefaultTreeModel(root,true);//根据root根节点并判断节点是否为叶子节点(指定方式判断)
        /**
         * 默认判断是否是叶子节点:如果该节点没有子节点,就为叶子节点。
         *指定方式方式判断是否是叶子节点:节点是否允许有子节点,如果不允许则为叶子节点,如果允许,就算没有子节点也不是叶子节点
         */
        JTree jt3 = new JTree(model2);

        DefaultTreeCellRenderer treeCellRenderer;//获得树节点的绘制对象
        treeCellRenderer = (DefaultTreeCellRenderer) jt3.getCellRenderer();
        treeCellRenderer.setLeafIcon(null);//设置叶子节点不使用图标
        treeCellRenderer.setClosedIcon(null);//设置节点折叠时不采用图标
        treeCellRenderer.setOpenIcon(null);//设置节点展开时不采用图标

        //运行时所有节点展开功能的实现代码
        Enumeration<?> enumeration;
        enumeration = root.preorderEnumeration();//按前序遍历所有树节点
        while (enumeration.hasMoreElements()){
            DefaultMutableTreeNode node;
            node = (DefaultMutableTreeNode) enumeration.nextElement();
            if (!node.isLeaf()){//判断是否为叶子节点
                //创建该节点的路径
                TreePath path = new TreePath(node.getPath());
                jt3.expandPath(path);//展开路径
            }
        }

        getContentPane().add(jt3,BorderLayout.EAST);
        setDefaultCloseOperation(3);
    }


}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

尢词

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

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

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

打赏作者

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

抵扣说明:

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

余额充值