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的结点,通过这种方法可以最大程度的改变结点的外观。