目录
一、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);
}
}
(其他功能待补,大家可以提出来一起讨论讨论)