疯狂JAVA讲义---第十二章:Swing编程(七)JTree树
2009-01-18 17:01
549 查看
树这东西给用户的感觉极为方便,但给程序员带来很大的麻烦,它是swing中最麻烦的控件之一。树要弄的好非常麻烦,图标的美化,层次的划分,各种事件的处理。。。对于初学者来说,就不要太讲究样式,下面举个粗糙的例子,eg
拖动,编辑树节点也是树的基本功能,下面就在上面例子的基础上,加上这些功能,eg
最后讲下如何修饰tree的图标,主要是通过拓展TreeCellRenderer来实现,eg
图标大家就自己搞几个吧,不搞也可以看到效果。明天我将讲下JTable,也是个麻烦的控件。
public class SimpleJTree { 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); //默认连线 //tree.putClientProperty("JTree.lineStyle" , "Angeled"); //没有连线 tree.putClientProperty("JTree.lineStyle" , "None"); //水平分隔线 //tree.putClientProperty("JTree.lineStyle" , "Horizontal"); //设置是否显示根节点的“展开/折叠”图标,默认是false tree.setShowsRootHandles(true); //设置节点是否可见,默认是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 SimpleJTree().init(); } }
拖动,编辑树节点也是树的基本功能,下面就在上面例子的基础上,加上这些功能,eg
public class EditJTree { JFrame jf; JTree tree; //上面JTree对象对应的model 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("南宁"); //定义需要被拖动的TreePath TreePath movePath; JButton addSiblingButton = new JButton("添加兄弟节点"); JButton addChildButton = new JButton("添加子节点"); JButton deleteButton = new JButton("删除节点"); JButton editButton = new JButton("编辑当前节点"); public void init() { 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() { //按下鼠标时候获得被拖动的节点 public void mousePressed(MouseEvent e) { //如果需要唯一确定某个节点,必须通过TreePath来获取。 TreePath tp = tree.getPathForLocation(e.getX(), e.getY()); if (tp != null) { movePath = tp; } } //鼠标松开时获得需要拖到哪个父节点 public void mouseReleased(MouseEvent e) { //根据鼠标松开时的TreePath来获取TreePath TreePath tp = tree.getPathForLocation(e.getX(), e.getY()); if (tp != null && movePath != null) { //阻止向子节点拖动 if (movePath.isDescendant(tp) && movePath != tp) { JOptionPane.showMessageDialog(jf, "目标节点是被移动节点的子节点,无法移动!", "非法操作", JOptionPane.ERROR_MESSAGE ); return; } //既不是向子节点移动,而且鼠标按下、松开的不是同一个节点 else if (movePath != tp) { System.out.println(tp.getLastPathComponent()); //add方法可以先将原节点从原父节点删除,再添加到新父节点中 ((DefaultMutableTreeNode)tp.getLastPathComponent()).add( (DefaultMutableTreeNode)movePath.getLastPathComponent()); movePath = null; tree.updateUI(); } } } }; tree.addMouseListener(ml); JPanel panel = new JPanel(); addSiblingButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { //获取选中节点 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 + 1); //--------下面代码实现显示新节点(自动展开父节点)------- //获取从根节点到新节点的所有节点 TreeNode[] nodes = model.getPathToRoot(newNode); //使用指定的节点数组来创建TreePath TreePath path = new TreePath(nodes); //显示指定TreePath tree.scrollPathToVisible(path); } }); panel.add(addSiblingButton); addChildButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { //获取选中节点 DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); //如果节点为空,直接返回 if (selectedNode == null) return; //创建一个新节点 DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新节点"); //直接通过model来添加新节点,则无需通过调用JTree的updateUI方法 //model.insertNodeInto(newNode, selectedNode, selectedNode.getChildCount()); //直接通过节点添加新节点,则需要调用tree的updateUI方法 selectedNode.add(newNode); //--------下面代码实现显示新节点(自动展开父节点)------- TreeNode[] nodes = model.getPathToRoot(newNode); TreePath path = new TreePath(nodes); tree.scrollPathToVisible(path); tree.updateUI(); } }); panel.add(addChildButton); deleteButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); if (selectedNode != null && selectedNode.getParent() != null) { //删除指定节点 model.removeNodeFromParent(selectedNode); } } }); panel.add(deleteButton); editButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { TreePath selectedPath = tree.getSelectionPath(); if (selectedPath != null) { //编辑选中节点 tree.startEditingAtPath(selectedPath); } } }); panel.add(editButton); jf.add(new JScrollPane(tree)); jf.add(panel , BorderLayout.SOUTH); jf.pack(); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.setVisible(true); } public static void main(String[] args) { new EditJTree().init(); } }
最后讲下如何修饰tree的图标,主要是通过拓展TreeCellRenderer来实现,eg
public class ExtendsDefaultTreeCellRenderer { 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 , "公司客户数据库")); //定义salaryDb的两个子节点 DefaultMutableTreeNode employee = new DefaultMutableTreeNode( new NodeData(DBObjectType.TABLE , "员工表")); DefaultMutableTreeNode attend = new DefaultMutableTreeNode( new NodeData(DBObjectType.TABLE , "考勤表")); //定义customerDb的一个子节点 DefaultMutableTreeNode contact = new DefaultMutableTreeNode( new NodeData(DBObjectType.TABLE , "联系方式表")); //定义employee的三个子节点 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()throws Exception { //通过add方法建立树节点之间的父子关系 root.add(salaryDb); root.add(customerDb); salaryDb.add(employee); salaryDb.add(attend); customerDb.add(contact); employee.add(id); employee.add(name); employee.add(gender); //以根节点创建树 tree = new JTree(root); //设置该JTree使用自定义的节点绘制器 tree.setCellRenderer(new MyRenderer()); //设置是否显示根节点的“展开/折叠”图标,默认是false tree.setShowsRootHandles(true); //设置节点是否可见,默认是true tree.setRootVisible(true); //设置使用Windows风格外观 UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); //更新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) throws Exception { new ExtendsDefaultTreeCellRenderer().init(); } } //定义一个NodeData类,用于封装节点数据 class NodeData { public int nodeType; public String nodeData; public NodeData(int nodeType , String nodeData) { this.nodeType = nodeType; this.nodeData = nodeData; } public String toString() { return nodeData; } } //定义一个接口,该接口里包含数据库对象类型的常量 interface DBObjectType { int ROOT = 0; int DATABASE = 1; int TABLE = 2; int COLUMN = 3; int INDEX = 4; } class MyRenderer extends DefaultTreeCellRenderer { //初始化5个图标 ImageIcon rootIcon = new ImageIcon("icon/root.gif"); ImageIcon databaseIcon = new ImageIcon("icon/database.gif"); ImageIcon tableIcon = new ImageIcon("icon/table.gif"); ImageIcon columnIcon = new ImageIcon("icon/column.gif"); ImageIcon indexIcon = new ImageIcon("icon/index.gif"); public 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; } }
图标大家就自己搞几个吧,不搞也可以看到效果。明天我将讲下JTable,也是个麻烦的控件。
相关文章推荐
- 疯狂JAVA讲义---第十二章:Swing编程(七)JTree树
- 疯狂JAVA讲义---第十二章:Swing编程(二)特殊容器
- 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条
- 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条
- 疯狂JAVA讲义---第十二章:Swing编程(一)基本组件
- 疯狂JAVA讲义---第十二章:Swing编程(六)微调控制器和列表框
- 疯狂JAVA讲义---第十二章:Swing编程(四)Applet和JApplet
- 疯狂JAVA讲义---第十二章:Swing编程(八)JTable表格
- 疯狂JAVA讲义---第十二章:Swing编程(三)拖放功能
- [疯狂Java讲义精粹] 第十二章|网络编程
- 疯狂JAVA讲义---第十三章:JDBC编程(上)
- 疯狂JAVA讲义---第十一章(中):AWT编程-常用组件和事件处理
- 疯狂JAVA讲义---第十一章(上):AWT编程-布局管理器
- java8--网络编程(java疯狂讲义3复习笔记)
- Java Swing编程:JTree树
- 疯狂JAVA讲义---第十三章:JDBC编程(下)
- java8--Mysql数据库与JDBC编程(java疯狂讲义3复习笔记)
- 疯狂JAVA讲义---第十一章(下):AWT编程-高级应用
- [疯狂Java笔记]图形用户界面、AWT、Swing简介
- 《Java 编程思想》--第十二章:通过异常处理错误