Java Swing編程:JTree樹
樹這東西給用戶的感覺極為方便,但給程序員帶來很大的麻煩,它是swing中最麻煩的控件之一。樹要弄的好非常麻煩,圖標(biāo)的美化,層次的劃分,各種事件的處理。。。對(duì)于初學(xué)者來說,就不要太講究樣式,下面舉個(gè)粗糙的例子,eg
- public class SimpleJTree
- {
- JFrame jf = new JFrame("簡單樹");
- JTree tree;
- //定義幾個(gè)初始節(jié)點(diǎn)
- 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方法建立樹節(jié)點(diǎn)之間的父子關(guān)系
- guangdong.add(foshan);
- guangdong.add(shantou);
- guangxi.add(guilin);
- guangxi.add(nanning);
- root.add(guangdong);
- root.add(guangxi);
- //以根節(jié)點(diǎn)創(chuàng)建樹
- tree = new JTree(root);
- //默認(rèn)連線
- //tree.putClientProperty("JTree.lineStyle" , "Angeled");
- //沒有連線
- tree.putClientProperty("JTree.lineStyle" , "None");
- //水平分隔線
- //tree.putClientProperty("JTree.lineStyle" , "Horizontal");
- //設(shè)置是否顯示根節(jié)點(diǎn)的“展開/折疊”圖標(biāo),默認(rèn)是false
- tree.setShowsRootHandles(true);
- //設(shè)置節(jié)點(diǎn)是否可見,默認(rèn)是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();
- }
- }
拖動(dòng),編輯樹節(jié)點(diǎn)也是樹的基本功能,下面就在上面例子的基礎(chǔ)上,加上這些功能,eg
- public class EditJTree
- {
- JFrame jf;
- JTree tree;
- //上面JTree對(duì)象對(duì)應(yīng)的model
- DefaultTreeModel model;
- //定義幾個(gè)初始節(jié)點(diǎn)
- 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("南寧");
- //定義需要被拖動(dòng)的TreePath
- TreePath movePath;
- JButton addSiblingButton = new JButton("添加兄弟節(jié)點(diǎn)");
- JButton addChildButton = new JButton("添加子節(jié)點(diǎn)");
- JButton deleteButton = new JButton("刪除節(jié)點(diǎn)");
- JButton editButton = new JButton("編輯當(dāng)前節(jié)點(diǎn)");
- 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對(duì)應(yīng)的TreeModel對(duì)象
- model = (DefaultTreeModel)tree.getModel();
- //設(shè)置JTree可編輯
- tree.setEditable(true);
- MouseListener ml = new MouseAdapter()
- {
- //按下鼠標(biāo)時(shí)候獲得被拖動(dòng)的節(jié)點(diǎn)
- public void mousePressed(MouseEvent e)
- {
- //如果需要唯一確定某個(gè)節(jié)點(diǎn),必須通過TreePath來獲取。
- TreePath tp = tree.getPathForLocation(e.getX(), e.getY());
- if (tp != null)
- {
- movePath = tp;
- }
- }
- //鼠標(biāo)松開時(shí)獲得需要拖到哪個(gè)父節(jié)點(diǎn)
- public void mouseReleased(MouseEvent e)
- {
- //根據(jù)鼠標(biāo)松開時(shí)的TreePath來獲取TreePath
- TreePath tp = tree.getPathForLocation(e.getX(), e.getY());
- if (tp != null && movePath != null)
- {
- //阻止向子節(jié)點(diǎn)拖動(dòng)
- if (movePath.isDescendant(tp) && movePath != tp)
- {
- JOptionPane.showMessageDialog(jf, "目標(biāo)節(jié)點(diǎn)是被移動(dòng)節(jié)點(diǎn)的子節(jié)點(diǎn),無法移動(dòng)!",
- "非法操作", JOptionPane.ERROR_MESSAGE );
- return;
- }
- //既不是向子節(jié)點(diǎn)移動(dòng),而且鼠標(biāo)按下、松開的不是同一個(gè)節(jié)點(diǎn)
- else if (movePath != tp)
- {
- System.out.println(tp.getLastPathComponent());
- //add方法可以先將原節(jié)點(diǎn)從原父節(jié)點(diǎn)刪除,再添加到新父節(jié)點(diǎn)中
- ((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)
- {
- //獲取選中節(jié)點(diǎn)
- DefaultMutableTreeNode selectedNode
- = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
- //如果節(jié)點(diǎn)為空,直接返回
- if (selectedNode == null) return;
- //獲取該選中節(jié)點(diǎn)的父節(jié)點(diǎn)
- DefaultMutableTreeNode parent
- = (DefaultMutableTreeNode)selectedNode.getParent();
- //如果父節(jié)點(diǎn)為空,直接返回
- if (parent == null) return;
- //創(chuàng)建一個(gè)新節(jié)點(diǎn)
- DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新節(jié)點(diǎn)");
- //獲取選中節(jié)點(diǎn)的選中索引
- int selectedIndex = parent.getIndex(selectedNode);
- //在選中位置插入新節(jié)點(diǎn)
- model.insertNodeInto(newNode, parent, selectedIndex + 1);
- //--------下面代碼實(shí)現(xiàn)顯示新節(jié)點(diǎn)(自動(dòng)展開父節(jié)點(diǎn))-------
- //獲取從根節(jié)點(diǎn)到新節(jié)點(diǎn)的所有節(jié)點(diǎn)
- TreeNode[] nodes = model.getPathToRoot(newNode);
- //使用指定的節(jié)點(diǎn)數(shù)組來創(chuàng)建TreePath
- TreePath path = new TreePath(nodes);
- //顯示指定TreePath
- tree.scrollPathToVisible(path);
- }
- });
- panel.add(addSiblingButton);
- addChildButton.addActionListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent event)
- {
- //獲取選中節(jié)點(diǎn)
- DefaultMutableTreeNode selectedNode
- = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
- //如果節(jié)點(diǎn)為空,直接返回
- if (selectedNode == null) return;
- //創(chuàng)建一個(gè)新節(jié)點(diǎn)
- DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新節(jié)點(diǎn)");
- //直接通過model來添加新節(jié)點(diǎn),則無需通過調(diào)用JTree的updateUI方法
- //model.insertNodeInto(newNode, selectedNode, selectedNode.getChildCount());
- //直接通過節(jié)點(diǎn)添加新節(jié)點(diǎn),則需要調(diào)用tree的updateUI方法
- selectedNode.add(newNode);
- //--------下面代碼實(shí)現(xiàn)顯示新節(jié)點(diǎn)(自動(dòng)展開父節(jié)點(diǎn))-------
- 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)
- {
- //刪除指定節(jié)點(diǎn)
- model.removeNodeFromParent(selectedNode);
- }
- }
- });
- panel.add(deleteButton);
- editButton.addActionListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent event)
- {
- TreePath selectedPath = tree.getSelectionPath();
- if (selectedPath != null)
- {
- //編輯選中節(jié)點(diǎn)
- 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的圖標(biāo),主要是通過拓展TreeCellRenderer來實(shí)現(xiàn),eg
- public class ExtendsDefaultTreeCellRenderer
- {
- JFrame jf = new JFrame("根據(jù)節(jié)點(diǎn)類型定義圖標(biāo)");
- JTree tree;
- //定義幾個(gè)初始節(jié)點(diǎn)
- DefaultMutableTreeNode root = new DefaultMutableTreeNode(
- new NodeData(DBObjectType.ROOT , "數(shù)據(jù)庫導(dǎo)航"));
- DefaultMutableTreeNode salaryDb = new DefaultMutableTreeNode(
- new NodeData(DBObjectType.DATABASE , "公司工資數(shù)據(jù)庫"));
- DefaultMutableTreeNode customerDb = new DefaultMutableTreeNode(
- new NodeData(DBObjectType.DATABASE , "公司客戶數(shù)據(jù)庫"));
- //定義salaryDb的兩個(gè)子節(jié)點(diǎn)
- DefaultMutableTreeNode employee = new DefaultMutableTreeNode(
- new NodeData(DBObjectType.TABLE , "員工表"));
- DefaultMutableTreeNode attend = new DefaultMutableTreeNode(
- new NodeData(DBObjectType.TABLE , "考勤表"));
- //定義customerDb的一個(gè)子節(jié)點(diǎn)
- DefaultMutableTreeNode contact = new DefaultMutableTreeNode(
- new NodeData(DBObjectType.TABLE , "聯(lián)系方式表"));
- //定義employee的三個(gè)子節(jié)點(diǎn)
- 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方法建立樹節(jié)點(diǎn)之間的父子關(guān)系
- root.add(salaryDb);
- root.add(customerDb);
- salaryDb.add(employee);
- salaryDb.add(attend);
- customerDb.add(contact);
- employee.add(id);
- employee.add(name);
- employee.add(gender);
- //以根節(jié)點(diǎn)創(chuàng)建樹
- tree = new JTree(root);
- //設(shè)置該JTree使用自定義的節(jié)點(diǎn)繪制器
- tree.setCellRenderer(new MyRenderer());
- //設(shè)置是否顯示根節(jié)點(diǎn)的“展開/折疊”圖標(biāo),默認(rèn)是false
- tree.setShowsRootHandles(true);
- //設(shè)置節(jié)點(diǎn)是否可見,默認(rèn)是true
- tree.setRootVisible(true);
- //設(shè)置使用Windows風(fēng)格外觀
- 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();
- }
- }
- //定義一個(gè)NodeData類,用于封裝節(jié)點(diǎn)數(shù)據(jù)
- 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;
- }
- }
- //定義一個(gè)接口,該接口里包含數(shù)據(jù)庫對(duì)象類型的常量
- interface DBObjectType
- {
- int ROOT = 0;
- int DATABASE = 1;
- int TABLE = 2;
- int COLUMN = 3;
- int INDEX = 4;
- }
- class MyRenderer extends DefaultTreeCellRenderer
- {
- //初始化5個(gè)圖標(biāo)
- 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)
- {
- //執(zhí)行父類默認(rèn)的節(jié)點(diǎn)繪制操作
- super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
- DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
- NodeData data = (NodeData)node.getUserObject();
- //根據(jù)數(shù)據(jù)節(jié)點(diǎn)里的nodeType數(shù)據(jù)決定節(jié)點(diǎn)圖標(biāo)
- 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;
- }
- //改變圖標(biāo)
- this.setIcon(icon);
- return this;
- }
- }
圖標(biāo)大家就自己搞幾個(gè)吧,不搞也可以看到效果。明天我將講下JTable,也是個(gè)麻煩的控件。
原文鏈接:http://blog.csdn.net/terryzero/article/details/3828045
【編輯推薦】