文章目录

  • 7.11 JTree、TreeModel实现树
    • 7.11.1 创建树
    • 7.11.2 拖动、编辑树结点
    • 7.11.3 监听结点事件
    • 7.11.4 使用DefaultTreeCellRenderer改变结点外观
    • 7.11.5 扩展DefaultTreeCellRenderer改变结点外观
    • 7.11.6 实现TreeCellRenderer接口改变结点外观

7.11 JTree、TreeModel实现树

树也是图形用户界面中使用非常广泛的 GUI 组件,例如使用 Windows 资源管理器时,将看到如下图所示的目录树:

如上图所示的树,代表计算机世界里的树,它从自然界实际的树抽象而来 。 计算机世界里的树是由一系列具有严格父子关系的节点组成的,每个节点既可以是其上一级节点的子节点,也可以是其下一级节点的父节点,因此同一个节点既可以是父节点,也可以是子节点(类似于一个人,他既是他儿子的父亲,又是他父亲的儿子)。

按照结点是否包含子结点,可以把结点分为下面两类:

​ 普通结点:包含子结点的结点;

​ 叶子结点:没有子结点的结点;

按照结点是否具有唯一的父结点,可以把结点分为下面两类:

​ 根结点:没有父结点的结点,计算机中,一棵树只能有一个根结点

​ 普通结点:具有唯一父结点的结点

使用 Swing 里的 Jtree 、 TreeModel 及其相关的辅助类可以很轻松地开发出计算机世界里的树。

7.11.1 创建树

Swing 使用 JTree 对 象来代表一棵树,JTree 树中结点可以使用 TreePath 来标识,该对象封装了当前结点及其所有的父结点。

当一个结点具有子结点时,该结点有两种状态:

​ 展开状态:当父结点处于展开状态时,其子结点是可见的;

​ 折叠状态: 当父结点处于折叠状态时,其子结点都是不可见的 。

如果某个结点是可见的,则该结点的父结点(包括直接的、间接的父结点)都必须处于展开状态,只要有任意一个父结点处于折叠状态,该结点就是不可见的 。

JTree常用构造方法:

JTree(TreeModel newModel):使用指定 的数据模型创建 JTree 对象,它默认显示根结点。
JTree(TreeNode root): 使用 root 作为根节 点创建 JTree 对象,它默认显示根结点 。
JTree(TreeNode root, boolean asksAllowsChildren): 使用root作为根结点创建JTree对象,
它默认显示根结点。
asksAllowsChildren 参数控制怎样的结点才算叶子结点,如果该参数为 true ,则只有当程序使用
setAllowsChildren(false)显式设置某个结点不允许添加子结点时(以后也不会拥有子结点) ,
该结点才会被 JTree 当成叶子结点:如果该参数为 false ,则只要某个结点当时没有子结点
(不管以后是否拥有子结点) ,该结点都会被 JTree 当成叶子结点。

TreeNode继承体系及使用:

在构建目录树时,可以先创建很多DefaultMutableTreeNode对象,并调用他们的add方法构建好子父级结构,最后根据根结点构建一个JTree即可。

案例:

​ 使用JTree和TreeNode完成下图效果:

演示代码:

public class SimpleJTree {JFrame jf = new JFrame("简单树");JTree tree;DefaultMutableTreeNode root;DefaultMutableTreeNode guangdong;DefaultMutableTreeNode guangxi;DefaultMutableTreeNode foshan;DefaultMutableTreeNode shantou;DefaultMutableTreeNode guilin;DefaultMutableTreeNode nanning;public void init(){//依次创建所有结点root = new DefaultMutableTreeNode("中国");guangdong = new DefaultMutableTreeNode("广东");guangxi = new DefaultMutableTreeNode("广西");foshan = new DefaultMutableTreeNode("佛山");shantou = new DefaultMutableTreeNode("汕头");guilin = new DefaultMutableTreeNode("桂林");nanning = new DefaultMutableTreeNode("南宁");//通过add()方法建立父子层级关系guangdong.add(foshan);guangdong.add(shantou);guangxi.add(guilin);guangxi.add(nanning);root.add(guangdong);root.add(guangxi);//依据根结点,创建JTreetree = new JTree(root);jf.add(new JScrollPane(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"):设置结点之间只有水平分割线
tree.setShowsRootHandles(true):设置根结点有"展开、折叠"图标
tree.setRootVisible(false):隐藏根结点

DefaultMutableTreeNode其他成员方法:

Enumeration breadthFirstEnumerationO/preorderEnumeration(): 按广度优先的顺序遍历以此结点为根的子树,并返回所有结点组成的枚举对象 。
Enumeration depthFirstEnumerationO/postorderEnumeration(): 按深度优先的顺序遍历以此结点为根的子树,并返回所有结点组成的枚举对象 。
DefaultMutableTreeNode getNextSibling(): 返回此结点的下一个兄弟结点 。
TreeNode getParent(): 返回此结点的父结点 。 如果此结点没有父结点,则返回null 。
TreeNode[] getPath(): 返回从根结点到达此结点的所有结点组成的数组。
DefaultMutableTreeNode getPreviousSibling(): 返回此结点的上一个兄弟结点。
TreeNode getRoot(): 返回包含此结点的树的根结点 。
TreeNode getSharedAncestor(DefaultMutableTreeNode aNode): 返回此结点和aNode最近的共同祖先 。
int getSiblingCount(): 返回此结点的兄弟结点数 。
boolean isLeaf(): 返回该结点是否是叶子结点 。
boolean isNodeAncestor(TreeNode anotherNode): 判断anotherNode是否是当前结点的祖先结点(包括父结点) 。
boolean isNodeChild(TreeNode aNode): 如果aNode是此结点的子结点,则返回true。
boolean isNodeDescendant(DefaultMutableTreeNode anotherNode): 如果 anotherNode 是此结点的后代,包括是此结点本身、此结点的子结点或此结点的子结点的后代,都将返回true 。
boolean isNodeRelated(DefaultMutableTreeNode aNode) : 当aNode和当前结点位于同一棵树中时返回 true 。
boolean isNodeSibling(TreeNode anotherNode): 返回anotherNode是否是当前结点的兄弟结点 。
boolean isRoot(): 返回当前结点是否是根结点 。
Enumeration pathFromAncestorEnumeration(TreeNode ancestor): 返回从指定祖先结点到当前结点的所有结点组成的枚举对象 。

7.11.2 拖动、编辑树结点

JTree 生成的树默认是不可编辑的,不可以添加、删除结点,也不可以改变结点数据 :如果想让某个 JTree 对象变成可编辑状态,则可以调用 JTree 的setEditable(boolean b)方法,传入 true 即可把这棵树变成可编辑的树(可以添加、删除结点,也可以改变结点数据) 。

编辑树结点的步骤:

  1. 获取当前被选中的结点:

获取当前被选中的结点,会有两种方式:
一:
通过JTree对象的某些方法,例如 TreePath getSelectionPath()等,得到一个TreePath对象,包含了从根结点到当前结点路径上的所有结点;
调用TreePath对象的 Object getLastPathComponent()方法,得到当前选中结点
二:
调用JTree对象的 Object getLastSelectedPathComponent() 方法获取当前被选中的结点

  1. 调用DefaultTreeModel数据模型有关增删改的一系列方法完成编辑,方法执行完后,会自动重绘JTree

案例:

​ 使用JTree以及DefaultTreeModel、DefaultMutableTreeNode、TreePath完成下图效果:

public class EditTree {JFrame jf ;JTree tree;//JTree关联的数据模型对象DefaultTreeModel model;//定义几个初始结点DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode("广东");DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode("广西");DefaultMutableTreeNode foshan = new DefaultMutableTreeNode("佛山");DefaultMutableTreeNode shantou = new DefaultMutableTreeNode("汕头");DefaultMutableTreeNode guilin = new DefaultMutableTreeNode("桂林");DefaultMutableTreeNode nanning = new DefaultMutableTreeNode("南宁");//定义需要被拖动的TreePathTreePath movePath;//定义按钮,完成操作JButton addSiblingBtn = new JButton("添加兄弟结点");JButton addChildBtn = new JButton("添加子结点");JButton deleteBtn = new JButton("删除结点");JButton editBtn = new JButton("编辑当前结点");public void init(){//通过add()方法建立父子层级关系guangdong.add(foshan);guangdong.add(shantou);guangxi.add(guilin);guangxi.add(nanning);root.add(guangdong);root.add(guangxi);jf = new JFrame("可编辑结点的树");tree = new JTree(root);//获取JTree关联的数据模型TreeModel对象model = (DefaultTreeModel) tree.getModel();//设置JTree可编辑tree.setEditable(true);//创建鼠标事件监听器MouseListener ml = new MouseAdapter() {//按下鼠标时,获得被拖动的结点@Overridepublic void mousePressed(MouseEvent e) {//如果需要唯一确定某个结点,则必须通过TreePath来获取TreePath tp = tree.getPathForLocation(e.getX(), e.getY());if (tp!=null){movePath = tp;}}//松开树表示,确定即将被拖入到的父结点@Overridepublic void mouseReleased(MouseEvent e) {TreePath tp = tree.getPathForLocation(e.getX(), e.getY());if (tp!=null && movePath!=null){//阻止向子结点拖动if (movePath.isDescendant(tp) && movePath!=tp){JOptionPane.showMessageDialog(jf,"目标结点是被移动结点的子结点,无法移动!","非法移动",JOptionPane.WARNING_MESSAGE);}//不是向子结点移动,并且鼠标按下和松开也不是同一个结点if (movePath!=tp){//add方法内部,先将该结点从原父结点删除,然后再把该结点添加到新结点中DefaultMutableTreeNode tartParentNode = (DefaultMutableTreeNode) tp.getLastPathComponent();DefaultMutableTreeNode moveNode = (DefaultMutableTreeNode) movePath.getLastPathComponent();tartParentNode.add(moveNode);movePath=null;tree.updateUI();}}}};//为JTree添加鼠标监听器tree.addMouseListener(ml);JPanel panel = new JPanel();addSiblingBtn.addActionListener(e -> {//获取选中结点DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();//如果结点为空,则直接返回if (selectedNode==null){return;}//获取该选中结点的父结点DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selectedNode.getParent();//如果父结点为空,则直接返回if (parent==null){return;}//创建一个新结点DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");//获取选中结点的索引int selectedIndex = parent.getIndex(selectedNode);//在选中位置插入新结点model.insertNodeInto(newNode,parent,selectedIndex);//----------显示新结点---------------//获取从根结点到新结点的所有结点TreeNode[] pathToRoot = model.getPathToRoot(newNode);//使用指定的结点数组创建TreePathTreePath treePath = new TreePath(pathToRoot);//显示指定的treePathtree.scrollPathToVisible(treePath);});panel.add(addSiblingBtn);addChildBtn.addActionListener(e -> {//获取选中结点DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();if (selectedNode==null){return ;}//创建新结点DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");//model.insertNodeInto(newNode,selectedNode,selectedNode.getChildCount());使用TreeModel的方法添加,不需要手动刷新UIselectedNode.add(newNode);//使用TreeNode的方法添加,需要手动刷新UI//显示新结点TreeNode[] pathToRoot = model.getPathToRoot(newNode);TreePath treePath = new TreePath(pathToRoot);tree.scrollPathToVisible(treePath);//手动刷新UItree.updateUI();});panel.add(addChildBtn);deleteBtn.addActionListener(e -> {DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();if (selectedNode!=null && selectedNode.getParent()!=null){model.removeNodeFromParent(selectedNode);}});panel.add(deleteBtn);//实现编辑结点的监听器editBtn.addActionListener(e -> {TreePath selectionPath = tree.getSelectionPath();if (selectionPath!=null){//编辑选中结点tree.startEditingAtPath(selectionPath);}});panel.add(editBtn);jf.add(new JScrollPane(tree));jf.add(panel, BorderLayout.SOUTH);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.pack();jf.setVisible(true);}public static void main(String[] args) {new EditTree().init();}
}

7.11.3 监听结点事件

修改JTree的选择模式:

JTree 专门提供了 一个 TreeSelectionModel 对象来保存该 JTree 选中状态的信息 。 也就是说,JTree组件背后隐藏了两个 model 对象 , 其中TreeModel 用于保存该 JTree 的所有节点数据 , 而TreeSelectionModel 用于保存该 JTree的所有选中状态的信息 。

程序可以改变 JTree 的选择模式 , 但必须先获取该 JTree 对应的 TreeSelectionMode1 对象 , 再调用该对象的 setSelectionMode(int mode);方法来设置该JTree的选择模式 ,其中model可以有如下3种取值:

  1. TreeSelectionModel.CONTIGUOUS_TREE_SELECTION: 可 以连续选中多个 TreePath 。
  2. TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION : 该选项对于选择没有任何限制 。
  3. TreeSelectionModel.SINGLE_TREE_SELECTION: 每次只能选择一个 TreePath 。

为JTree添加监听器:

  1. addTreeExpansionListener(TreeExpansionListener tel) : 添加树节点展开/折叠事件的监听器。
  2. addTreeSelectionListener(TreeSelectionListener tsl) : 添加树节点选择事件的监听器。

案例:

​ 实现下图效果:

演示代码:

public class SelectJTree {JFrame jf = new JFrame("监听树的选择事件");JTree tree;DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode("广东");DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode("广西");DefaultMutableTreeNode foshan = new DefaultMutableTreeNode("佛山");DefaultMutableTreeNode shantou = new DefaultMutableTreeNode("汕头");DefaultMutableTreeNode guilin = new DefaultMutableTreeNode("桂林");DefaultMutableTreeNode nanning = new DefaultMutableTreeNode("南宁");JTextArea eventTxt = new JTextArea(5, 20);public void init() {//通过add()方法建立父子层级关系guangdong.add(foshan);guangdong.add(shantou);guangxi.add(guilin);guangxi.add(nanning);root.add(guangdong);root.add(guangxi);tree = new JTree(root);//添加监听器tree.addTreeSelectionListener(e -> {if (e.getOldLeadSelectionPath()!=null){eventTxt.append("原选中结点的路径:"+e.getOldLeadSelectionPath().toString()+"\n");}eventTxt.append("新选中结点的路径:"+e.getNewLeadSelectionPath().toString()+"\n");});tree.setShowsRootHandles(true);tree.setRootVisible(true);Box box = Box.createHorizontalBox();box.add(new JScrollPane(tree));box.add(new JScrollPane(eventTxt));jf.add(box);jf.pack();jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);}public static void main(String[] args) {new SelectJTree().init();}
}

7.11.4 使用DefaultTreeCellRenderer改变结点外观

JTree默认的外观是比较单一的,它提供了如下几种改变结点外观的方式:

  1. 使用 DefaultTreeCellRenderer 直接改变节点的外观,这种方式可 以 改变整棵树所有节点 的字体、颜色和图标 。
  2. 为 JTree 指定 DefaultTreeCellRenderer 的扩展类对象作为 JTree 的节点绘制器,该绘制器负责为不同节点使用不同的字体、颜色和图标。通常使用这种方式来改变节点的外观 。
  3. 为 JTree 指定一个实现 TreeCellRenderer 接口的节点绘制器,该绘制器可以为不同的节点自由绘制任意内容,这是最复杂但最灵活的节点绘制器 。

第 一种方式最简单 , 但灵活性最差 ,因为它会改变整棵树所有节点的外观 。 在这种情况下 , Jtree的所有节点依然使用相同的图标 ,相当于整体替换了 Jtree 中 节点的所有默认图标 。 用户指定 的节点图标未必就比 JTree 默认的图标美观 。

DefaultTreeCellRenderer 提供了如下几个方法来修改节点的外观:

setBackgroundNonSelectionColor(Color newColor): 设置用于非选定节点的背景颜色 。
setBackgroundSelectionColor(Color newColor): 设置节点在选中状态下的背景颜色 。
setBorderSelectionColor(Color newColor): 设置选中状态下节点的边框颜色 。
setClosedIcon(Icon newIcon): 设置处于折叠状态下非叶子节点的图标 。
setFont(Font font) : 设置节点文本 的 字体。
setLeaflcon(Icon newIcon): 设置叶子节点的图标 。
setOpenlcon(Icon newlcon): 设置处于展开状态下非叶子节 点的图标。
setTextNonSelectionColor(Color newColor): 设置绘制非选中状态下节点文本的颜色 。
setTextSelectionColor(Color newColor): 设置绘制选中状态下节点文本的颜色 。

案例:

​ 使用DefaultTreeCellRenderer完成下图效果:

演示代码:

public class ChangeAllCellRender {JFrame jf = new JFrame("改变所有结点外观");JTree tree;DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode("广东");DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode("广西");DefaultMutableTreeNode foshan = new DefaultMutableTreeNode("佛山");DefaultMutableTreeNode shantou = new DefaultMutableTreeNode("汕头");DefaultMutableTreeNode guilin = new DefaultMutableTreeNode("桂林");DefaultMutableTreeNode nanning = new DefaultMutableTreeNode("南宁");public void init(){//通过add()方法建立父子层级关系guangdong.add(foshan);guangdong.add(shantou);guangxi.add(guilin);guangxi.add(nanning);root.add(guangdong);root.add(guangxi);tree = new JTree(root);//创建一个DefaultTreeCellRenderer对象DefaultTreeCellRenderer cellRenderer = new DefaultTreeCellRenderer();//设置非选定结点的背景颜色cellRenderer.setBackgroundNonSelectionColor(new Color(220,220,220));//设置选中结点的背景色cellRenderer.setBackgroundSelectionColor(new Color(140,140,140));//设置选中状态下结点的边框颜色cellRenderer.setBorderSelectionColor(Color.BLACK);//设置处于折叠状态下非叶子结点的图标cellRenderer.setClosedIcon(new ImageIcon("D:\\mygit\\JavaBasicLearning\\src\\com\\xjtu\\chapter07\\swing\\img\\tree\\close.gif"));//设置结点文本的字体cellRenderer.setFont(new Font("SansSerif", Font.BOLD,16));//设置叶子结点图标cellRenderer.setLeafIcon(new ImageIcon("D:\\mygit\\JavaBasicLearning\\src\\com\\xjtu\\chapter07\\swing\\img\\tree\\leaf.gif"));//设置处于展开状态下非叶子结点图标跑cellRenderer.setOpenIcon(new ImageIcon("D:\\mygit\\JavaBasicLearning\\src\\com\\xjtu\\chapter07\\swing\\img\\tree\\open.gif"));//设置绘制非选中状态下结点文本颜色cellRenderer.setTextNonSelectionColor(new Color(255,0,0));//设置选中状态下结点的文本颜色cellRenderer.setTextSelectionColor(new Color(0,0,255));tree.setCellRenderer(cellRenderer);tree.setShowsRootHandles(true);tree.setRootVisible(true);jf.add(new JScrollPane(tree));jf.pack();jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);}public static void main(String[] args) {new ChangeAllCellRender().init();}}

7.11.5 扩展DefaultTreeCellRenderer改变结点外观

DefaultTreeCellRenderer 实现类实现了TreeCellRenderer接口,该接口里只有 一个用于绘制节点内容的方法: getTreeCellRendererComponent() , 该方法负责绘制 JTree 节点 。学习JList的时候,如果要绘制JList的列表项外观的内容,需要实现ListCellRenderer 接口,通过重写getTreeCellRendererComponent()方法返回一个Component 对象 , 该对象就是 JTree 的节点组件 。两者之间非常类似

DefaultTreeCellRende rer 类继承了JLabel,实现 getTreeCellRendererComponent()方法时返回 this ,即返回一个特殊的 JLabel 对象 。 如果需要根据节点内容来改变节点的外观,则可以再次扩展DefaultTreeCellRenderer 类,并再次重写它提供的 getTreeCellRendererComponent()方法。

案例:

​ 自定义类继承DefaultTreeCellRenderer,重写getTreeCellRendererComponent()方法,实现下图效果:

演示代码:

public class ExtendsDefaultCellTreeRenderer {JFrame jf = new JFrame("根据结点类型定义图标");JTree tree;//定义几个初始结点DefaultMutableTreeNode root = new DefaultMutableTreeNode(new NodeData(DBObjectType.ROOT,"数据库导航"));DefaultMutableTreeNode salaryDb = new DefaultMutableTreeNode(new NodeData(DBObjectType.DATABASE,"公司工资数据库"));DefaultMutableTreeNode customerDb = new DefaultMutableTreeNode(new NodeData(DBObjectType.DATABASE,"公司客户数据库"));DefaultMutableTreeNode employee = new DefaultMutableTreeNode(new NodeData(DBObjectType.TABLE,"员工表"));DefaultMutableTreeNode attend = new DefaultMutableTreeNode(new NodeData(DBObjectType.TABLE,"考勤表"));DefaultMutableTreeNode concat = new DefaultMutableTreeNode(new NodeData(DBObjectType.TABLE,"联系方式表"));DefaultMutableTreeNode id = new DefaultMutableTreeNode(new NodeData(DBObjectType.INDEX,"员工ID"));DefaultMutableTreeNode name = new DefaultMutableTreeNode(new NodeData(DBObjectType.COLUMN,"姓名"));DefaultMutableTreeNode gender = new DefaultMutableTreeNode(new NodeData(DBObjectType.COLUMN,"性别"));public void init(){//通过结点的add方法,建立结点的父子关系root.add(salaryDb);root.add(customerDb);salaryDb.add(employee);salaryDb.add(attend);customerDb.add(concat);concat.add(id);concat.add(name);concat.add(gender);tree = new JTree(root);tree.setCellRenderer(new MyRenderer());tree.setShowsRootHandles(true);tree.setRootVisible(true);//设置使用windows外观风格try {UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");} catch (Exception e) {e.printStackTrace();}//更新JTree的UI外观SwingUtilities.updateComponentTreeUI(tree);jf.add(new JScrollPane(tree));jf.pack();jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);}public static void main(String[] args) {new ExtendsDefaultCellTreeRenderer().init();}class MyRenderer extends DefaultTreeCellRenderer {//初始化5个图标ImageIcon rootIcon = new ImageIcon("D:\\mygit\\JavaBasicLearning\\src\\com\\xjtu\\chapter07\\swing\\img\\tree\\root.gif");ImageIcon databaseIcon = new ImageIcon("D:\\mygit\\JavaBasicLearning\\src\\com\\xjtu\\chapter07\\swing\\img\\tree\\database.gif");ImageIcon tableIcon = new ImageIcon("D:\\mygit\\JavaBasicLearning\\src\\com\\xjtu\\chapter07\\swing\\img\\tree\\table.gif");ImageIcon columnIcon = new ImageIcon("D:\\mygit\\JavaBasicLearning\\src\\com\\xjtu\\chapter07\\swing\\img\\tree\\column.gif");ImageIcon indexIcon = new ImageIcon("D:\\mygit\\JavaBasicLearning\\src\\com\\xjtu\\chapter07\\swing\\img\\tree\\index.gif");@Overridepublic Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {//执行父类默认的绘制结点操作super.getTreeCellRendererComponent(tree,value,sel,expanded,leaf,row,hasFocus);DefaultMutableTreeNode  node = (DefaultMutableTreeNode) value;NodeData data = (NodeData) node.getUserObject();//根据结点数据中的nodeType决定结点的图标ImageIcon icon = null;switch (data.nodeType){case DBObjectType.ROOT:icon = rootIcon;break;case DBObjectType.DATABASE:icon = databaseIcon;break;case DBObjectType.TABLE:icon = tableIcon;break;case DBObjectType.COLUMN:icon = columnIcon;break;case DBObjectType.INDEX:icon = indexIcon;break;}//改变图标this.setIcon(icon);return this;}}//定义一个NodeData类,用于封装结点数据class NodeData{public int nodeType;public String nodeData;public NodeData(int nodeType, String nodeData) {this.nodeType = nodeType;this.nodeData = nodeData;}@Overridepublic String toString() {return this.nodeData;}}//定义一个接口,该接口里包含数据库对象类型的常量interface  DBObjectType{int ROOT=0;int DATABASE=1;int TABLE=2;int COLUMN=3;int INDEX=4;}}

7.11.6 实现TreeCellRenderer接口改变结点外观

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

案例:

​ 自定义类,继承JPanel类,实现TreeCellRenderer接口,完成下图效果:

演示代码:

public class CustomerTreeNode {JFrame jf = new JFrame("定制树的结点");JTree tree;//定义几个初始结点DefaultMutableTreeNode friends = new DefaultMutableTreeNode("我的好友");DefaultMutableTreeNode qingzhao = new DefaultMutableTreeNode("李清照");DefaultMutableTreeNode suge = new DefaultMutableTreeNode("苏格拉底");DefaultMutableTreeNode libai = new DefaultMutableTreeNode("李白");DefaultMutableTreeNode nongyu = new DefaultMutableTreeNode("弄玉");DefaultMutableTreeNode hutou = new DefaultMutableTreeNode("虎头");public void init() {friends.add(qingzhao);friends.add(suge);friends.add(libai);friends.add(nongyu);friends.add(hutou);tree = new JTree(friends);tree.setShowsRootHandles(true);tree.setRootVisible(true);tree.setCellRenderer(new ImageCellRenderer());jf.add(new JScrollPane(tree));jf.pack();jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);}public static void main(String[] args) {new CustomerTreeNode().init();}class ImageCellRenderer extends JPanel implements TreeCellRenderer {private ImageIcon icon;private String name;//定义绘制单元格时的背景色private Color background;//定义绘制单元格时的前景色private Color foreground;@Overridepublic Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {icon = new ImageIcon("D:\\mygit\\JavaBasicLearning\\src\\com\\xjtu\\chapter07\\swing\\img\\tree\\" + value + ".gif");name = value.toString();background = hasFocus ? new Color(140, 200, 235) : new Color(255, 255, 255);foreground = hasFocus ? new Color(255,255,3) : new Color(0,0,0);//返回当前JPanel作为结点return this;}//重写paintComponent改变JPanel的外观@Overrideprotected void paintComponent(Graphics g) {int imageWidth = icon.getImage().getWidth(null);int imageHeight = icon.getImage().getHeight(null);g.setColor(background);g.fillRect(0,0,getWidth(),getHeight());g.setColor(foreground);//绘制好友图标g.drawImage(icon.getImage(),getWidth()/2-imageWidth/2,10,null);//绘制好友姓名g.setFont(new Font("SansSerif", Font.BOLD,18));g.drawString(name,getWidth()/2-name.length()*10,imageHeight+30);}//设置当前组件结点最佳大小@Overridepublic Dimension getPreferredSize() {return new Dimension(80,80);}}
}

[ XJTUSE ]JAVA语言基础知识——7.11 JTree、TreeModel实现树相关推荐

  1. [ XJTUSE ]JAVA语言基础知识——2.2 Java基本数据类型

    文章目录 2.2 Java基本数据类型 1.布尔型 2.字符类型 3.整型 4.浮点数类型 5.数据类型转换 2.2 Java基本数据类型 Java提供的数据类型如下: 1.布尔型 布尔型只有true ...

  2. [ XJTUSE ]JAVA语言基础知识——7.12 JTable实现表格

    文章目录 7.12 JTable实现表格 7.12.1 创建简单表格 7.12.2 TableModel和监听器 7.12.3 TableColumnModel和监听器 7.12.4 实现列排序 7. ...

  3. 计算机java语言教程,计算机JAVA教程二讲Java语言基础知识.doc

    计算机JAVA教程二讲Java语言基础知识 2.1简单数据类型 2.1.1 标识符和保留字 1.标识符 程序员对程序中的各个元素加以命名时使用的命名记号称为标识符(identifier).Java语言 ...

  4. java入门学习笔记(二)—— Eclipse入门学习之快捷键、java语言基础知识之各类关键字及其用法简析

    一.Eclipse入门学习 1. 快捷键 对于一个编辑器,快捷键必不可少,是十分好用且有效的工具. 对于一个初学者,首先掌握了如下快捷键. (很多通用的快捷键不多说) Ctrl + / -- 注释当前 ...

  5. Java语言基础知识(一)

    前言 Java是一门高级计算机语言,由美国Sun公司(Stanford University Network)在1995年推出(现Sun公司已经被Oracle公司收购 ).要想学好Java,基础是至关 ...

  6. Java 语言基础知识

    1.Java语言概述 Java是一门面向对象的编程语言,其吸收了C++语言的各种优点,还把C++里难以理解的多继承.指针等一系列概念摒弃掉.其功能强大,简单易用.可跨平台.其有三种技术架构:JAVAE ...

  7. java语言基础知识(完整版)

    目录 一.java开发环境 二.名词解释 1.JVM 三.eclipse 1.定义 四.注释 1.解释性文本 2.其他注释 五.变量 4.命名规则 六.八种数据基本类型 七.数据类型之间的转换 1.自 ...

  8. java语言基础知识笔记

    目录 1.Java开发环境: 1)java编译运行过程:----------常见面试题 *  2)名词解释:------------------常见面试题 3)配置环境变量:------------- ...

  9. [ XJTUSE ]JAVA语言进阶知识—— 8.6 多线程

    文章目录 8.6 多线程 1.不相关的线程 2.相关但无须同步的线程 3.同步线程 4.交互式线程 8.6 多线程 大多数网络应用程序一般都有多个线程同时运行,与多进程不同,由于多线程在同一个进程内运 ...

  10. java语言基础知识

最新文章

  1. 建立可扩展的silverlight应用框架 step-4
  2. HandlerThread和IntentService源码解析
  3. GNU/Linux下LVM配置管理以及快照卷、物理卷、卷组、逻辑卷的创建和删除
  4. CentOS 安装Zabbix 手记
  5. 三体智能革命_《三体》之人类的科技文明发展历史其实很诡异
  6. 人脸识别中Softmax-based Loss的演化史
  7. Windows 10 安装SVN 不显示状态图标--解决方法
  8. android togglebutton 自定义,自定义控件之-----ToggleButton
  9. clip_region_relclip_region
  10. 企业电子邮箱的地址格式
  11. 让用户画像见效,我找到了这个突破口……
  12. 数据库插入数据时报错 1364 - Field ‘house_name‘ doesn‘t have a default value
  13. jquery 遍历java对象,js/jquery遍历对象和数组的方法分析【forEach,map与each方法】...
  14. 电脑生成siri语音_给电脑里装个Siri!海尔智能语音系统体验
  15. java怪物掉落_我的世界地下城boss打法及掉落物品一览
  16. eclipse 找不到configure working sets选项
  17. 这些年正Android - 身在他乡
  18. 面向对象 编写 银行系统 实战
  19. (转)超详细iOS证书申请流程
  20. AxMath安装教程

热门文章

  1. Docker基础:指定USER的容器中获得root用户的方法
  2. Java app接入微信和支付宝支付
  3. 牛啊!微信支持发送彩色红包~~
  4. 数学三次危机(四)第一次数学危机
  5. 上古卷轴5捏脸php导入,上古卷轴5捏脸预设导入 上古卷轴5捏脸预设怎么导入
  6. HUSTOJ超级详细部署文档
  7. 知识产权与标准规范: 著作权法、计算机软件保护条例、商标权、不正当竞争法、招投标法、采购法、合同法
  8. [INFO] Using ‘UTF-8‘ encoding to copy filtered resources.错误
  9. sd卡 格式化 命令 linux,在Linux命令行上格式化SD卡、USB驱动器、闪存驱动器的方法...
  10. HTTP/3 ,它来了。