[ XJTUSE ]JAVA语言基础知识——7.11 JTree、TreeModel实现树
文章目录
- 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 即可把这棵树变成可编辑的树(可以添加、删除结点,也可以改变结点数据) 。
编辑树结点的步骤:
- 获取当前被选中的结点:
获取当前被选中的结点,会有两种方式:
一:
通过JTree对象的某些方法,例如 TreePath getSelectionPath()等,得到一个TreePath对象,包含了从根结点到当前结点路径上的所有结点;
调用TreePath对象的 Object getLastPathComponent()方法,得到当前选中结点
二:
调用JTree对象的 Object getLastSelectedPathComponent() 方法获取当前被选中的结点
- 调用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种取值:
- TreeSelectionModel.CONTIGUOUS_TREE_SELECTION: 可 以连续选中多个 TreePath 。
- TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION : 该选项对于选择没有任何限制 。
- TreeSelectionModel.SINGLE_TREE_SELECTION: 每次只能选择一个 TreePath 。
为JTree添加监听器:
- addTreeExpansionListener(TreeExpansionListener tel) : 添加树节点展开/折叠事件的监听器。
- 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默认的外观是比较单一的,它提供了如下几种改变结点外观的方式:
- 使用 DefaultTreeCellRenderer 直接改变节点的外观,这种方式可 以 改变整棵树所有节点 的字体、颜色和图标 。
- 为 JTree 指定 DefaultTreeCellRenderer 的扩展类对象作为 JTree 的节点绘制器,该绘制器负责为不同节点使用不同的字体、颜色和图标。通常使用这种方式来改变节点的外观 。
- 为 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实现树相关推荐
- [ XJTUSE ]JAVA语言基础知识——2.2 Java基本数据类型
文章目录 2.2 Java基本数据类型 1.布尔型 2.字符类型 3.整型 4.浮点数类型 5.数据类型转换 2.2 Java基本数据类型 Java提供的数据类型如下: 1.布尔型 布尔型只有true ...
- [ XJTUSE ]JAVA语言基础知识——7.12 JTable实现表格
文章目录 7.12 JTable实现表格 7.12.1 创建简单表格 7.12.2 TableModel和监听器 7.12.3 TableColumnModel和监听器 7.12.4 实现列排序 7. ...
- 计算机java语言教程,计算机JAVA教程二讲Java语言基础知识.doc
计算机JAVA教程二讲Java语言基础知识 2.1简单数据类型 2.1.1 标识符和保留字 1.标识符 程序员对程序中的各个元素加以命名时使用的命名记号称为标识符(identifier).Java语言 ...
- java入门学习笔记(二)—— Eclipse入门学习之快捷键、java语言基础知识之各类关键字及其用法简析
一.Eclipse入门学习 1. 快捷键 对于一个编辑器,快捷键必不可少,是十分好用且有效的工具. 对于一个初学者,首先掌握了如下快捷键. (很多通用的快捷键不多说) Ctrl + / -- 注释当前 ...
- Java语言基础知识(一)
前言 Java是一门高级计算机语言,由美国Sun公司(Stanford University Network)在1995年推出(现Sun公司已经被Oracle公司收购 ).要想学好Java,基础是至关 ...
- Java 语言基础知识
1.Java语言概述 Java是一门面向对象的编程语言,其吸收了C++语言的各种优点,还把C++里难以理解的多继承.指针等一系列概念摒弃掉.其功能强大,简单易用.可跨平台.其有三种技术架构:JAVAE ...
- java语言基础知识(完整版)
目录 一.java开发环境 二.名词解释 1.JVM 三.eclipse 1.定义 四.注释 1.解释性文本 2.其他注释 五.变量 4.命名规则 六.八种数据基本类型 七.数据类型之间的转换 1.自 ...
- java语言基础知识笔记
目录 1.Java开发环境: 1)java编译运行过程:----------常见面试题 * 2)名词解释:------------------常见面试题 3)配置环境变量:------------- ...
- [ XJTUSE ]JAVA语言进阶知识—— 8.6 多线程
文章目录 8.6 多线程 1.不相关的线程 2.相关但无须同步的线程 3.同步线程 4.交互式线程 8.6 多线程 大多数网络应用程序一般都有多个线程同时运行,与多进程不同,由于多线程在同一个进程内运 ...
- java语言基础知识
最新文章
- 建立可扩展的silverlight应用框架 step-4
- HandlerThread和IntentService源码解析
- GNU/Linux下LVM配置管理以及快照卷、物理卷、卷组、逻辑卷的创建和删除
- CentOS 安装Zabbix 手记
- 三体智能革命_《三体》之人类的科技文明发展历史其实很诡异
- 人脸识别中Softmax-based Loss的演化史
- Windows 10 安装SVN 不显示状态图标--解决方法
- android togglebutton 自定义,自定义控件之-----ToggleButton
- clip_region_relclip_region
- 企业电子邮箱的地址格式
- 让用户画像见效,我找到了这个突破口……
- 数据库插入数据时报错 1364 - Field ‘house_name‘ doesn‘t have a default value
- jquery 遍历java对象,js/jquery遍历对象和数组的方法分析【forEach,map与each方法】...
- 电脑生成siri语音_给电脑里装个Siri!海尔智能语音系统体验
- java怪物掉落_我的世界地下城boss打法及掉落物品一览
- eclipse 找不到configure working sets选项
- 这些年正Android - 身在他乡
- 面向对象 编写 银行系统 实战
- (转)超详细iOS证书申请流程
- AxMath安装教程
热门文章
- Docker基础:指定USER的容器中获得root用户的方法
- Java app接入微信和支付宝支付
- 牛啊!微信支持发送彩色红包~~
- 数学三次危机(四)第一次数学危机
- 上古卷轴5捏脸php导入,上古卷轴5捏脸预设导入 上古卷轴5捏脸预设怎么导入
- HUSTOJ超级详细部署文档
- 知识产权与标准规范: 著作权法、计算机软件保护条例、商标权、不正当竞争法、招投标法、采购法、合同法
- [INFO] Using ‘UTF-8‘ encoding to copy filtered resources.错误
- sd卡 格式化 命令 linux,在Linux命令行上格式化SD卡、USB驱动器、闪存驱动器的方法...
- HTTP/3 ,它来了。