失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Java图形化界面编程超详细知识点(9)——Swing_树

Java图形化界面编程超详细知识点(9)——Swing_树

时间:2023-01-17 04:23:03

相关推荐

Java图形化界面编程超详细知识点(9)——Swing_树

目录

6 JTree、TreeModel实现树

6.1 创建树

6.2 编辑树结点

6.3 监听结点事件

6.4 使用DefaultTreeCellRenderer改变结点外观

6.5 扩展DefaultTreeCellRenderer改变结点外观

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

6 JTree、TreeModel实现树

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

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

按照节点是否包含子节点,可把节点分为两类:

普通节点:包含子节点的节点;

叶子节点:没有子节点的节点;

按照节点是否具有唯一的父节点,可把节点分为两类:

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

普通节点:具有唯一父节点的节点;

6.1 创建树

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

JTree常用构造方法:

JTree(TreeModel newModel);使用指定的数据模型来创建JTree对象,它默认显示根节点

JTree(TreeNode root);使用root作为根节点创建JTree对象,它默认显示根节点

JTree(TreeNode root,boolean askAllowsChildren);使用root作为根节点创建JTree对象,它默认显示根节点。askAllowsChildren参数控制怎样的节点才算叶子节点,若参数为true,则只有当程序使用

setAllowsChildren(false);显式设置某个节点不允许添加子节点时(以后也不会有子节点),该节点才会被JTree当成叶子节点,如果该参数为false,则只要某个节点当时没有子节点(不管以后有没有子节点),该节点都会被JTree当成叶子节点

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

案例:

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

public class SimpleJTree {JFrame jf = new JFrame("简单树");public void init(){//创建DefaultMutableTreeNode对象代表结点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("南宁");//组装结点之间的关系root.add(guangDong);root.add(guangXi);guangDong.add(foShan);guangDong.add(shanTou);guangXi.add(guiLin);guangXi.add(nanNing);//创建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();}}

6.2 编辑树结点

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

编辑树结点的步骤:

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

获取当前被选中的结点,会有两种方式;

一:通过JTree对象的某些方法,例如TreePath getSelectionPath()等,得到一个TreePath对象,包含了从根结点到当前结点路径上的所有结点;

调用TreePath对象的Object getLastPathComponent()方法,得到当前选中结点

二:调用JTree对象的Object getLastSelectedPathComponent()方法获取当前被选中的结点

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

案例:

使用JTree及DEfaultTreeModel、DefaultMutableTreeNode、TreePath完成下图效果:

public class EditTree {JFrame jf = new JFrame("可编辑结点的树");//定义几个初始结点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("南宁");//定义按钮,完成操作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);JTree tree = new JTree(root);//完成树的结点编辑的代码tree.setEditable(true);DefaultTreeModel model = (DefaultTreeModel) tree.getModel();//处理添加addSiblingBtn.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {//添加兄弟结点逻辑//1.获取当前选中的结点DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();if (selectedNode == null) {return;}//2.获取当前结点的父结点DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) selectedNode.getParent();if (parentNode == null) {return;}//3.创建新结点DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");//4.把新结点通过父结点进行添加int index = parentNode.getIndex(selectedNode);model.insertNodeInto(newNode, parentNode, index);//5.显示新结点TreeNode[] pathToRoot = model.getPathToRoot(newNode);TreePath treePath = new TreePath(pathToRoot);tree.scrollPathToVisible(treePath);//6.重绘treetree.updateUI();}});addChildBtn.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {//为选中结点添加子节点//1.获取选中结点DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();if (selectedNode == null) {return;}//2.创建新结点DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");//3.把新结点添加到当前结点中selectedNode.add(newNode);//4.显示新结点TreeNode[] pathToRoot = model.getPathToRoot(newNode);TreePath treePath = new TreePath(pathToRoot);tree.scrollPathToVisible(treePath);//5.重绘UItree.updateUI();}});//处理删除deleteBtn.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();if (selectedNode != null && selectedNode.getParent() != null) {model.removeNodeFromParent(selectedNode);}}});//处理编辑editBtn.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {//获取当前选中结点的路径TreePath selectionPath = tree.getSelectionPath();//判断如果路径不为空,则设置该路径的最后一个结点可编辑if (selectionPath != null) {tree.startEditingAtPath(selectionPath);}}});jf.add(new JScrollPane(tree));JPanel panel = new JPanel();panel.add(addSiblingBtn);panel.add(addChildBtn);panel.add(deleteBtn);panel.add(editBtn);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();}}

6.3 监听结点事件

为JTree添加监听器:

1.addTreeExpansionListener(TreeExpansionListener tel);添加树节点展开/折叠事件的监听器

2.addTreeSelectionListener(TreeSelectionListener tsl);添加树节点选择事件的监听器

修改JTree的选择模式:

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

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

1.TreeSelectionModel.CONTIGUOUS_TREE_SELECTION;可以连续选中多个TreePath

2.TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION;该选项对于选择没有任何限制

3.TreeSelectionModel.SINGLE_TREE_SELECTION;每次只能选一个TreePath

案例:

实现下图效果:

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);//TODO 设置选择模式TreeSelectionModel selectionModel = tree.getSelectionModel();selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);//TODO 设置监听器tree.addTreeSelectionListener(new TreeSelectionListener() {@Overridepublic void valueChanged(TreeSelectionEvent e) {//把当前选中结点的路径显示到文本域中TreePath newLeadSelectionPath = e.getNewLeadSelectionPath();eventTxt.append(newLeadSelectionPath.toString()+"\n");}});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();}}

6.4 使用DefaultTreeCellRenderer改变结点外观

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

1.使用DefaultTreeCellRenderer直接改变结点的外观,这种方式可以改变整棵树所有结点的字体、颜色和图标。

2.为JTree指定DefaultTreeCellRenderer的扩展类对象作为JTree的结点绘制器,该绘制器负责为不同结点使用不同的字体,颜色和图标。通常使用这种方式来改变结点外观。

3.为JTree指定一个实现TreeCellRenderer接口的结点绘制器,该绘制器可以为不同的结点自由绘制任意内容,这是最复杂但最灵活的结点绘制器。

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

setBackgroundNonSelectionColor(Color newColor);设置用于非选定结点的背景颜色

setBackgroundSelectionColor(Color newColor);设置结点再选中状态下的背景颜色

setBorderSelectionColor(Color newColor);设置选中状态下结点的边框颜色

setClosedIcon(Icon newIcon);设置处于折叠状态下非叶子结点的图标

setFont(Font font);设置结点文本的字体

setLeafIcon(Icon newIcon);设置叶子结点的图标

setOpenIcon(Icon newIcon);设置处于展开状态下非叶子结点的图标

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 renderer = new DefaultTreeCellRenderer();//设置非选定结点的背景颜色renderer.setBackgroundNonSelectionColor(new Color(220,220,220));//设置选中结点的背景色renderer.setBackgroundSelectionColor(new Color(140,140,140));//设置选中状态下结点的边框颜色renderer.setBorderSelectionColor(Color.BLACK);//设置处于折叠状态下非叶子结点的图标renderer.setClosedIcon(new ImageIcon("E:\\GUISwing\\img\\tree\\close.gif"));//设置结点文本的字体renderer.setFont(new Font("StSong",Font.BOLD,16));//设置叶子结点图标renderer.setLeafIcon(new ImageIcon("E:\\GUISwing\\img\\tree\\leaf.png"));//设置处于展开状态下非叶子结点图标renderer.setOpenIcon(new ImageIcon("E:\\GUISwing\\img\\tree\\open.gif"));//设置绘制非选中状态下结点文本颜色renderer.setTextNonSelectionColor(new Color(255,0,0));//设置选中状态下结点的文本颜色renderer.setTextSelectionColor(new Color(0,0,255));//把结点绘制器设置给树对象tree.setCellRenderer(renderer);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();}}

6.5 扩展DefaultTreeCellRenderer改变结点外观

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

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

案例:

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

public class ExtendsDefaultCellTreeRenderer {JFrame jf = new JFrame("根据结点类型定义图标");JTree tree;//初始化5个图标ImageIcon rootIcon = new ImageIcon("E:\\GUISwing\\img\\tree\\root.gif");ImageIcon databaseIcon = new ImageIcon("E:\\GUISwing\\img\\tree\\database.gif");ImageIcon tableIcon = new ImageIcon("E:\\GUISwing\\img\\tree\\table.gif");ImageIcon columnIcon = new ImageIcon("E:\\GUISwing\\img\\tree\\column.gif");ImageIcon indexIcon = new ImageIcon("E:\\GUISwing\\img\\tree\\index.gif");//定义一个NodeData类,用于封装结点数据class NodeData{public ImageIcon icon;public String name;public NodeData(ImageIcon icon, String name) {this.icon = icon;this.name = name;}}//定义几个初始结点DefaultMutableTreeNode root = new DefaultMutableTreeNode(new NodeData(rootIcon,"数据库导航"));DefaultMutableTreeNode salaryDb = new DefaultMutableTreeNode(new NodeData(databaseIcon,"公司工资数据库"));DefaultMutableTreeNode customerDb = new DefaultMutableTreeNode(new NodeData(databaseIcon,"公司客户数据库"));DefaultMutableTreeNode employee = new DefaultMutableTreeNode(new NodeData(tableIcon,"员工表"));DefaultMutableTreeNode attend = new DefaultMutableTreeNode(new NodeData(tableIcon,"考勤表"));DefaultMutableTreeNode concat = new DefaultMutableTreeNode(new NodeData(tableIcon,"联系方式表"));DefaultMutableTreeNode id = new DefaultMutableTreeNode(new NodeData(indexIcon,"员工ID"));DefaultMutableTreeNode name = new DefaultMutableTreeNode(new NodeData(columnIcon,"姓名"));DefaultMutableTreeNode gender = new DefaultMutableTreeNode(new NodeData(columnIcon,"性别"));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);//TODO 通过扩展DefaultTreeCellRenderer修改外观tree.setCellRenderer(new MyRenderer());jf.add(new JScrollPane(tree));jf.pack();jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);}//自定义类,继承DefaultTreeCellRenderer,完成结点的绘制private class MyRenderer extends DefaultTreeCellRenderer{//重写方法@Overridepublic Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {//当前类间接的继承了JLabel这个组件类,展示一张图片和一些配套的文字//Object value这个参数,代表的就是即将要绘制的结点//获取当前结点DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;//获取到当前即将绘制的结点的名称和图标NodeData nodeData = (NodeData) node.getUserObject();//通过setText方法和setIcon方法完成设置this.setText(nodeData.name);this.setIcon(nodeData.icon);return this;}}public static void main(String[] args) {new ExtendsDefaultCellTreeRenderer().init();}}

6.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);//TODO 设置结点绘制器MyRenderer renderer = new MyRenderer();tree.setCellRenderer(renderer);jf.add(new JScrollPane(tree));jf.pack();jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);}//自定义类,实现TreeCellRenderer接口,绘制组件private class MyRenderer 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) {//给成员变量设置值this.icon = new ImageIcon("E:\\GUISwing\\img\\tree\\"+value.toString()+".gif");this.name = value.toString();this.background = hasFocus? new Color(144,200,225) : new Color(255,255,255);this.foreground = hasFocus? new Color(255,255,3) : new Color(0,0,0);return this;}//通过重写getPreferenceSize方法,指定当前Jpanel组件的大小@Overridepublic Dimension getPreferredSize() {return new Dimension(80,80);}@Overridepublic void paint(Graphics g) {//绘制组件内容int iconWidth = this.icon.getIconWidth();int iconHeight = this.icon.getIconHeight();//填充背景g.setColor(background);g.fillRect(0,0,getWidth(),getHeight());//绘制头像g.drawImage(this.icon.getImage(),getWidth()/2 - iconWidth/2,10,null);//绘制昵称g.setColor(foreground);g.setFont(new Font("StSong",Font.BOLD,18));g.drawString(this.name,getWidth()/2-this.name.length()*20/2,iconHeight+30);}}public static void main(String[] args) {new CustomerTreeNode().init();}}

如果觉得《Java图形化界面编程超详细知识点(9)——Swing_树》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。