目录

一、JTree树的常用方法

二、JTree树的创建

三、JTree创建文件树

四、JTree创建下拉列表树

五、JTree实现其它功能

 1、设置当鼠标移入节点时设置节点选中

 2、JTree实现拖拽节点功能


一、JTree树的常用方法

常用set方法:
//设置树模型
tree.setModel();
//使用根节点给树设置模型
tree.setModel(new DefaultTreeModel(root));
//设置树是否可编辑
tree.setEditable();
//设置根节点的树柄是否可见
tree.setShowsRootHandles();
//设置根节点是否可见
tree.setRootVisible();
//设置指定路径为选中
tree.setSelectionPath(TreePath path);
//设置多个指定路径为选中
tree.setSelectionRows(TreePath[] paths);
//设置指定行为选中
tree.setSelectionRow(int row);
//设置指定多行为选中
tree.setSelectionRows(int[] rows);
//给树设置渲染器(可通过渲染器给节点设置图标和节点名称)
tree.setCellRenderer(TreeCellRenderer x);
 常用get方法:
//获取选中节点的路径
        tree.getSelectionPath();
        //获取指定坐标对应节点的路径
        tree.getPathForLocation(int x, int y);
        //获取指定行的路径
        tree.getPathForRow(int row);
        //获取指定坐标对应的行
        tree.getRowForLocation(int x, int y);
        //获取指定坐标对应的节点路径
        tree.getPathForLocation(int x, int y);
        //获取指定行的大小和坐标
        tree.getRowBounds(int row);
        //获取指定路径的节点大小和坐标
        tree.getPathBounds(TreePath path);
        //获取树的总行数
        tree.getRowCount();
 树的展开收起操作:
//展开指定行
        tree.expandRow(int row);
        //展开指定路径
        tree.expandPath(TreePath path);
        //收起指定行
        tree.collapseRow(int row));
        //收起指定路径
        tree.collapsePath(TreePath path);
 JTree树的事件:
//给树添加展开收起监听事件
        tree.addTreeExpansionListener(new TreeExpansionListener() {
            @Override
            public void treeExpanded(TreeExpansionEvent event) {
                //展开动作
            }
            @Override
            public void treeCollapsed(TreeExpansionEvent event) {
                //收起动作
            }
        });

//给树添加选中事件
tree.addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent e) {
                //节点选中动作
            }
        });
 树的渲染:
//设置树收起时的树柄图标
        UIManager.put("Tree.collapsedIcon", icon);
        //设置树展开时的树柄图标
        UIManager.put("Tree.expandedIcon", icon);

        //使用默认渲染器渲染树
        DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
        renderer.setLeafIcon();//给树设置叶子节点图标
        renderer.setClosedIcon();//设置树收起时的图标
        renderer.setOpenIcon();//设置树展开时的图标
        tree.setCellRenderer(renderer);

二、JTree树的创建

//直接通过一个根节点创建一棵树
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("根节点");
        JTree tree = new JTree(root);

        //通过 setModel 给树设置新的节点
        DefaultMutableTreeNode root2 = new DefaultMutableTreeNode("根节点2");
        tree.setModel(new DefaultTreeModel(root2));

        

        //一般都会把树放进滚动面板里
        //如果时多棵树可以把多棵树放到一个面板里,再将该面板加到滚动面板中
        //或者设置树的根节点不可见,将多棵树转换为一棵树的多个节点
        JScrollPane pane = new JScrollPane(tree);

三、JTree创建文件树

import javax.swing.*;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.ExpandVetoException;
import java.awt.*;
import java.io.File;

public class Main {
    public static void main(String[] args) {
        JFrame jf = new JFrame();
        jf.setSize(600,600);
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jf.setLocationRelativeTo(null);

        FileTree tree = createTree("F:\\blog");

        JScrollPane pane = new JScrollPane(tree);

        jf.setContentPane(pane);
        jf.setVisible(true);

    }


    //传入根文件路径,返回一颗文件树
    public static FileTree createTree(String rootPath) {

        //设置节点收起时的图标
        UIManager.put("Tree.collapsedIcon", new ImageIcon("src/main/resources/right.png"));
        //设置节点展开时的图标
        UIManager.put("Tree.expandedIcon", new ImageIcon("src/main/resources/down.png"));
        File file = new File(rootPath);

        FileNode fileNode = new FileNode(file.getName(), file, FileSystemView.getFileSystemView().getSystemIcon(file));

        DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(fileNode);
        FileTree fileTree = new FileTree(treeNode);


        File[] files = fileNode.file.listFiles();

        for (int i = 0; i < files.length; i++) {
            FileNode childFileNode = new FileNode(files[i].getName(), files[i], FileSystemView.getFileSystemView().getSystemIcon(files[i]));
            DefaultMutableTreeNode childTreeNode = new DefaultMutableTreeNode(childFileNode);
            treeNode.add(childTreeNode);
        }

        fileTree.setCellRenderer(new FileTreeRenderer());

        return fileTree;
    }
}




//节点对象,保存节点名称,文件和节点图标
class FileNode{
    public String name;
    public File file;
    public Icon icon;

    public boolean isLode;//判断当前节点是否已加载


    public FileNode(String name, File file, Icon icon){
        this.name=name;
        this.file = file;
        this.icon = icon;
    }
}

class FileTree extends JTree {

    public FileTree(DefaultMutableTreeNode treeNode) {
        super(treeNode);
        setRootVisible(true);
        setShowsRootHandles(true);


        //当树展开时触发事件,实现懒加载
        addTreeWillExpandListener(new TreeWillExpandListener() {
            @Override
            public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
                DefaultMutableTreeNode lastPathComponent = (DefaultMutableTreeNode) event.getPath().getLastPathComponent();

                FileNode fileNode = (FileNode) lastPathComponent.getUserObject();

                //当前节点为加载的情况才需要加载
                if (!fileNode.isLode) {
                    lodeNext2Node(lastPathComponent);
                    fileNode.isLode = true;
                }

            }

            @Override
            public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {

            }
        });
    }


    /**
     * 遍历参数节点的孩子节点,给每个孩子节点加载节点
     *
     * @param treeNode
     */

    public void lodeNext2Node(DefaultMutableTreeNode treeNode) {

        for (int i = 0; i < treeNode.getChildCount(); i++) {
            DefaultMutableTreeNode child = (DefaultMutableTreeNode) treeNode.getChildAt(i);
            FileNode childFileNode = (FileNode) child.getUserObject();//拿到节点对象
            File file = childFileNode.file;//通过节点对象获取对应的文件

            //遍历该文件的子文件,如果不为空则创建新的节点对象并加到当前节点
            File[] files = file.listFiles();
            if (files != null && files.length > 0) {
                for (File f : files) {
                    FileNode fileNode = new FileNode(f.getName(), f, FileSystemView.getFileSystemView().getSystemIcon(f));
                    if (f.isDirectory()) {
                        child.add(new DefaultMutableTreeNode(fileNode));
                    }

                }
            }
        }

    }


}

//自定义渲染器类,设置节点的图标和名称
class FileTreeRenderer extends DefaultTreeCellRenderer {
    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
        JLabel label = (JLabel) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);

        DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;

        FileNode fileNode = (FileNode) node.getUserObject();
        label.setText(fileNode.name);
        label.setIcon(fileNode.icon);

        return label;
    }
}

四、JTree创建下拉列表树

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

public class Main {
    public static void main(String[] args) {
        JFrame jf = new JFrame();
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jf.setSize(500, 500);
        jf.setLocationRelativeTo(null);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("根节点");

        DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("子节点1");
        DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("子节点2");

        DefaultMutableTreeNode node11 = new DefaultMutableTreeNode("子节点11");
        DefaultMutableTreeNode node12 = new DefaultMutableTreeNode("子节点12");
        DefaultMutableTreeNode node21 = new DefaultMutableTreeNode("子节点21");
        DefaultMutableTreeNode node22 = new DefaultMutableTreeNode("子节点22");

        node1.add(node11);
        node1.add(node12);
        node2.add(node21);
        node2.add(node22);

        root.add(node1);
        root.add(node2);

        JTree tree = new JTree(root);


        MyComboBox myComboBox = new MyComboBox(tree);
        myComboBox.setPreferredSize(new Dimension(200,30));

        JPanel panel = new JPanel();
        panel.add(myComboBox);

        jf.setContentPane(panel);
        jf.setVisible(true);
    }
}
import javax.swing.*;
import javax.swing.plaf.basic.ComboPopup;
import javax.swing.plaf.metal.MetalComboBoxUI;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.*;

public class MyComboBox extends JComboBox {

    private JTree tree;


    public MyComboBox(JTree tree) {
        this.tree = tree;
        this.setRenderer(new JTreeComboBoxRenderer(tree));
        this.setUI(new MetalJTreeComboBoxUI());
    }

    public JTree getTree() {
        return tree;
    }

    public void setSelectedItem(Object o) {

        tree.setSelectionPath((TreePath) o);
        getModel().setSelectedItem(o);

    }
}

class MetalJTreeComboBoxUI extends MetalComboBoxUI {
    protected ComboPopup createPopup() {
        return new TreePopup(comboBox);
    }
}


class JTreeComboBoxRenderer extends DefaultListCellRenderer {
    private JTree tree;

    public JTreeComboBoxRenderer(JTree tree) {
        this.tree = tree;
    }

    public Component getListCellRendererComponent(JList list, Object value,
                                                  int index, boolean isSelected, boolean cellHasFocus) {
        if (value != null) {
            TreePath path = (TreePath) value;
            TreeNode node = (TreeNode) path.getLastPathComponent();
            value = node;
            TreeCellRenderer r = tree.getCellRenderer();
            JLabel lb = (JLabel) r.getTreeCellRendererComponent(tree,
                    value, isSelected, false, node.isLeaf(), index,
                    cellHasFocus);
            return lb;
        }
        return super.getListCellRendererComponent(list, value, index,
                isSelected, cellHasFocus);
    }
}


class TreePopup extends JPopupMenu implements ComboPopup {
    protected MyComboBox comboBox;
    protected JScrollPane scrollPane;

    protected MouseMotionListener mouseMotionListener;
    protected MouseListener mouseListener;
    private MouseListener treeSelectListener = new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
            JTree tree = (JTree) e.getSource();
            TreePath tp = tree.getPathForLocation(e.getPoint().x,
                    e.getPoint().y);
            if (tp == null) {
                return;
            }

            comboBox.setSelectedItem(tp);
            if (comboBox.isVisible()) {
                togglePopup();
            }

            MenuSelectionManager.defaultManager().clearSelectedPath();
        }
    };

    public TreePopup(JComboBox comboBox) {
        this.comboBox = (MyComboBox) comboBox;
        setBorder(BorderFactory.createLineBorder(Color.black));
        setLayout(new BorderLayout());
        setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled());
        JTree tree = ((MyComboBox) comboBox).getTree();

        JPanel panel = new JPanel(new BorderLayout());
        panel.setBackground(Color.WHITE);


        tree.addMouseListener(treeSelectListener);
        panel.add(tree, BorderLayout.CENTER);


        scrollPane = new JScrollPane(panel);
        scrollPane.setBorder(null);
        add(scrollPane, BorderLayout.CENTER);
    }

    public void show() {
        updatePopup();
        show(comboBox, 0, comboBox.getHeight());


        comboBox.getTree().requestFocus();

    }

    public void hide() {
        setVisible(false);
        comboBox.firePropertyChange("popupVisible", true, false);
    }

    protected JList list = new JList();

    public JList getList() {
        return list;
    }

    public MouseMotionListener getMouseMotionListener() {
        if (mouseMotionListener == null) {
            mouseMotionListener = new MouseMotionAdapter() {
            };
        }
        return mouseMotionListener;
    }

    public KeyListener getKeyListener() {
        return null;
    }

    public void uninstallingUI() {
    }

    public MouseListener getMouseListener() {
        if (mouseListener == null) {
            mouseListener = new InvocationMouseHandler();
        }
        return mouseListener;
    }

    protected void togglePopup() {
        if (isVisible()) {
            hide();
        } else {
            show();
        }
    }

    protected void updatePopup() {
        setPreferredSize(new Dimension(comboBox.getSize().width, 200));

    }

    protected class InvocationMouseHandler extends MouseAdapter {
        public void mousePressed(MouseEvent e) {
            if (!SwingUtilities.isLeftMouseButton(e) || !comboBox.isEnabled()) {
                return;
            }
            if (comboBox.isEditable()) {
                Component comp = comboBox.getEditor().getEditorComponent();
                if ((!(comp instanceof JComponent))
                        || ((JComponent) comp).isRequestFocusEnabled()) {
                    comp.requestFocus();
                }
            } else if (comboBox.isRequestFocusEnabled()) {
                comboBox.requestFocus();
            }
            togglePopup();
        }
    }
}

五、JTree实现其它功能

 1、设置当鼠标移入节点时设置节点选中

tree.addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {

                TreePath pathForLocation = tree.getPathForLocation(50, e.getY());

                if (pathForLocation != null) {
                    tree.setSelectionPath(pathForLocation);
                }else {
                    tree.setSelectionPath(null);
                }
            }

        });
        tree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {

                Dimension dim = tree.getSize();

                if (e.getX() < 0 || e.getY() < 0 || e.getX() >= dim.getWidth() || e.getY() >= dim.getHeight()) {
                    tree.setSelectionPath(null);
                }
            }
        });

2、JTree实现拖拽节点功能

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.*;
import java.io.IOException;


public class DragTest {


    public static void main(String[] args) {

        //FlatLightLaf.setup();//使用FlatLightLaf主题库

        JFrame jf = new JFrame();
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jf.setSize(800, 800);
        jf.setLocationRelativeTo(null);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("根节点");

        DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("子节点1");
        DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("子节点2");

        DefaultMutableTreeNode node11 = new DefaultMutableTreeNode("子节点11");
        DefaultMutableTreeNode node12 = new DefaultMutableTreeNode("子节点12");
        DefaultMutableTreeNode node21 = new DefaultMutableTreeNode("子节点21");
        DefaultMutableTreeNode node22 = new DefaultMutableTreeNode("子节点22");

        node1.add(node11);
        node1.add(node12);
        node2.add(node21);
        node2.add(node22);

        root.add(node1);
        root.add(node2);

        JTree tree = new JTree(root);
        tree.setShowsRootHandles(true);
        

        //使用FlatLightLaf中的方法设置选中的节点显示整行背景
        //tree.putClientProperty("JTree.wideSelection", true);

        //获取并设置拖拽源
        DragSource dragSource = DragSource.getDefaultDragSource();
        dragSource.createDefaultDragGestureRecognizer(tree, DnDConstants.ACTION_MOVE, new DragGestureListener() {
            @Override
            public void dragGestureRecognized(DragGestureEvent dge) {
                DefaultMutableTreeNode select = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

                Transferable transferable = new Transferable() {
                    @Override
                    public DataFlavor[] getTransferDataFlavors() {
                        return new DataFlavor[0];
                    }

                    @Override
                    public boolean isDataFlavorSupported(DataFlavor flavor) {
                        return false;
                    }

                    @Override
                    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
                        return select;  //保存并返回选中的节点
                    }
                };

                //设置拖动时的图片,通过 Robot 截取 节点图片

                //获取选中节点的位置和大小
                int x = tree.getLocationOnScreen().x;
                int y = tree.getLocationOnScreen().y + tree.getPathBounds(tree.getSelectionPath()).y;
                int width = tree.getSize().width;
                int height = 21;

                //使用 Robot 类中的 createScreenCapture 方法截取指定区域图片
                final Robot robot;
                try {
                    robot = new Robot();
                } catch (AWTException e) {
                    throw new RuntimeException(e);
                }
                Image image = robot.createScreenCapture(new Rectangle(x, y, width, height));


                dge.startDrag(DragSource.DefaultMoveDrop, image, new Point(), transferable, null);

            }
        });


        //新建并获取拖拽目标
        new DropTarget(tree, DnDConstants.ACTION_MOVE, new DropTargetAdapter() {
            @Override
            public void drop(DropTargetDropEvent dtde) {

                //获取目标位置
                TreePath path = tree.getPathForLocation(dtde.getLocation().x, dtde.getLocation().y);


                if (path != null){
                    try {
                        DefaultMutableTreeNode sourceNode = (DefaultMutableTreeNode) dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
                        DefaultMutableTreeNode targetNode = (DefaultMutableTreeNode) path.getLastPathComponent();

                        if (sourceNode != targetNode){
                            targetNode.add(sourceNode);
                            tree.expandPath(path);//拖到目标位置后展开目标节点
                        }

                        tree.updateUI();
                    } catch (UnsupportedFlavorException e) {
                        throw new RuntimeException(e);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }

            }
        });


        tree.setPreferredSize(new Dimension(500, 500));
        JPanel panel = new JPanel(new BorderLayout());

        panel.add(tree,BorderLayout.CENTER);
        jf.setContentPane(panel);
        jf.setVisible(true);

    }

}

(其他功能待补,大家可以提出来一起讨论讨论)