精通java swing開發樹(Tree)

++ 樹(Tree)的使用與介紹

10-1:使用JTree組件:
    java.lang.Object
      --java.awt.Component
--java.awt.Container
        --javax.swing.JComponent
         --javax.swing.JTree
JTree構造函數:
JTree():建立一棵系統預設的樹。
JTree(Hashtable value):利用Hashtable建立樹,不顯示root node(根節點).
JTree(Object[] value):利用Object Array建立樹,不顯示root node.
JTree(TreeModel newModel):利用TreeModel建立樹。
JTree(TreeNode root):利用TreeNode建立樹。
JTree(TreeNode root,boolean asksAllowsChildren):利用TreeNode建立樹,並決
定是否允許子節點的存在.
JTree(Vector value):利用Vector建立樹,不顯示root node.

範例:
 InitalTree.java
 
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class InitalTree{
   public InitalTree(){
    JFrame f=new JFrame("TreeDemo");
    Container contentPane=f.getContentPane();
   
    JTree tree=new JTree();
    JScrollPane scrollPane=new JScrollPane();
    scrollPane.setViewportView(tree);
   
    contentPane.add(scrollPane);
    f.pack();
    f.setVisible(true);
    f.addWindowListener(new WindowAdapter(){
      public void windowClosing(WindowEvent e){
        System.exit(0);
      }
    });
   } 
   public static void main(String[] args){
     new InitalTree();
   }
}

10-2:以Hashtable構造JTree:
    上面的例子對我們並沒有裨的幫助,因為各個節點的數據均是java的預設值,
而非我們自己設置的。因此我們需利用其他JTree
構造函數來輸入我們想要的節點數據。以下範例我們以Hashtable當作JTree的數據
輸入:
範例:TreeDemo1.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class TreeDemo1{
   public TreeDemo1(){
     JFrame f=new JFrame("TreeDemo1");
     Container contentPane=f.getContentPane();
   
     String[] s1={"公司文件","個人信件","私人文件"};
     String[] s2={"本機磁盤(C:)","本機磁盤(D:)","本機磁盤(E:)"};
     String[] s3={"奇摩站","職棒消息","網絡書店"};
   
     Hashtable hashtable1=new Hashtable();
     Hashtable hashtable2=new Hashtable();
     hashtable1.put("我的公文包",s1);
     hashtable1.put("我的電腦",s2);
     hashtable1.put("收藏夾",hashtable2);
     hashtable2.put("網站列表",s3);
   
     Font font = new Font("Dialog", Font.PLAIN, 12);
Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
    /**定義widnows界面**/
     while (keys.hasMoreElements()) {
          Object key = keys.nextElement();
          if (UIManager.get(key) instanceof Font) {
              UIManager.put(key, font);
          }
    }
    try{
     
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
    }catch(Exception el){
       System.exit(0);
    }
    /**定義widnows界面**/
     JTree tree=new JTree(hashtable1);
     JScrollPane scrollPane=new JScrollPane();
     scrollPane.setViewportView(tree);
    contentPane.add(scrollPane);
    f.pack();
    f.setVisible(true);
    f.addWindowListener(new WindowAdapter(){
      public void windowClosing(WindowEvent e){
        System.exit(0);
      }
    });
   } 
   public static void main(String[] args){
     new TreeDemo1();
   }
}

純XP界面的設置:

10-3:以TreeNode構造JTree:
    JTree上的每一個節點就代表一個TreeNode對象,TreeNode本身是一個
Interface,裡面定義了7個有關節點的方法,例如判斷是否
為樹葉節點、有幾個子節點(getChildCount())、父節點為何(getparent())等等、
這些方法的定義你可以在javax.swing.tree的
package中找到,讀者可自行查閱java api文件。在實際的應用上,一般我們不會
直接實作此界面,而是採用java所提供的
DefaultMutableTreeMode類,此類是實作MutableTreeNode界面而來,並提供了其
他許多實用的方法。MutableTreeNode本身也是一
個Interface,且繼承了TreeNode界面此類主要是定義一些節點的處理方式,例如新
增節點(insert())、刪除節點(remove())、設置
節點(setUserObject())等。整個關係如下圖:
   
TreeNode----extends--->MutableTreeNode---implements---DefaultMutableTreeNode

   接下來我們來看如何利DefaultMutableTreeNode來建立JTree,我們先來看
DefaultMutableTreeNode的構造函數:

DefaultMutableTreeNode構造函數:
DefaultMutableTreeNode():建立空的DefaultMutableTreeNode對象。
DefaultMutableTreeNode(Object userObject):建立DefaultMutableTreeNode對
象,節點為userObject對象。
DefaultMutableTreeNode(Object userObject,Boolean allowsChildren):建立
DefaultMutableTreeNode對象,節點為userObject對
                                 象並決定此節點是否允許具有子節點。
   以下為利用DefaultMutableTreeNode建立JTree的範例:TreeDemo2.java
     此程式"資源管理器"為此棵樹的根節點.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
public class TreeDemo2{
   public TreeDemo2(){
     JFrame f=new JFrame("TreeDemo2");
     Container contentPane=f.getContentPane();
   
     DefaultMutableTreeNode root=new DefaultMutableTreeNode("資源管理器");
     DefaultMutableTreeNode node1=new DefaultMutableTreeNode("我的公文包");
     DefaultMutableTreeNode node2=new DefaultMutableTreeNode("我的電腦");
     DefaultMutableTreeNode node3=new DefaultMutableTreeNode("收藏夾");
     DefaultMutableTreeNode node4=new DefaultMutableTreeNode("Readme");
     root.add(node1);
     root.add(node2);
     root.add(node3);
     root.add(node4);
   
     DefaultMutableTreeNode leafnode=new DefaultMutableTreeNode("公司文件");
     node1.add(leafnode);
     leafnode=new DefaultMutableTreeNode("私人文件");
     node1.add(leafnode);
     leafnode=new DefaultMutableTreeNode("個人信件");
   
     leafnode=new DefaultMutableTreeNode("本機磁盤(C:)");
     node2.add(leafnode);
     leafnode=new DefaultMutableTreeNode("本機磁盤(D:)");
     node2.add(leafnode);
     leafnode=new DefaultMutableTreeNode("本機磁盤(E:)");
     node2.add(leafnode);
   
     DefaultMutableTreeNode node31=new DefaultMutableTreeNode("網站列表");
     node3.add(node31);
   
     leafnode=new DefaultMutableTreeNode("奇摩站");
     node31.add(leafnode);
     leafnode=new DefaultMutableTreeNode("職棒消息");
     node31.add(leafnode);
     leafnode=new DefaultMutableTreeNode("網絡書店");
     node31.add(leafnode);
   
     JTree tree=new JTree(root);
     JScrollPane scrollPane=new JScrollPane();
     scrollPane.setViewportView(tree);
   
     contentPane.add(scrollPane);
    f.pack();
    f.setVisible(true);
    f.addWindowListener(new WindowAdapter(){
      public void windowClosing(WindowEvent e){
        System.exit(0);
      }
    });
   } 
   public static void main(String[] args){
     new TreeDemo2();
   }
}

10-4:以TreeModel構造JTree.
    除了以節點的觀念(TreeNode)建立樹之外,你可以用data model的模式建立
樹。樹的data model稱為TreeModel,用此模式的好處
是可以觸發相關的樹事件,來處理樹可能產生的一些變動。TreeModel是一個
interface,裡面定義了8種方法;如果你是一個喜歡自己
動手做的人,或是你想顯示的數據格式很複雜,你可以考慮直接實作TreeModel界
面中所定義的方法來構造出JTree.TreeModel界面
的方法如下所示:
TreeModel方法:
void      addTreeModelListener(TreeModelListener l):增加一個
TreeModelListener來監控TreeModelEvent事件。
Object    getChild(Object parent,int index):返回子節點。
int       getChildCount(Object parent):返回子節點數量.
int       getIndexOfChild(Object parent,Object child):返回子節點的索引值。
Object    getRoot():返回根節點。
boolean   isLeaf(Object node):判斷是否為樹葉節點。
void      removeTreeModelListener(TreeModelListener l):刪除
TreeModelListener。
void      valueForPathChanged(TreePath path,Object newValue):當用戶改變
Tree上的值時如何應對。

    你可以實作出這8種方法,然後構造出自己想要的JTree,不過在大部份的情況下
我們通常不會這樣做,畢竟要實作出這8種方法不
是件很輕鬆的事,而且java本身也提供了一個預設模式,叫做DefaultTreeModel,
這個類已經實作了TreeModel界面,也另外提供許
多實用的方法。利用這個預設模式,我們便能很方便的構造出JTree出來了。下面
為DefaultTreeModel的構造函數與範例:
DefaultTreeModel構造函數:
DefaultTreeModel(TreeNode root):建立DefaultTreeModel對象,並定出根節點。
DefaultTreeModel(TreeNode root,Boolean asksAllowsChildren):建立具有根節
點的DefaultTreeModel對象,並決定此節點是否允
                        許具有子節點。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
import com.incors.plaf.alloy.*;//組件的下載網址http://www.incors.com
/lookandfeel/
/*將alloy.jar放在c:/j2sdk1.4.0/jre/lib/ext/目錄下.
  */
public class TreeDemo3
{
     public TreeDemo3()
     {
         JFrame f = new JFrame("TreeDemo");
         Container contentPane = f.getContentPane();
       
       
         DefaultMutableTreeNode root = new DefaultMutableTreeNode("資源管
理器");
         DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("我的
公文包");
         DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的
電腦");
         DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夾");
         DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme");
       
         DefaultTreeModel treeModel = new DefaultTreeModel(root);

         /*DefaultTreeModel類所提供的insertNodeInto()方法加入節點到父節點
的數量.
          *利用DefaultMutableTreeNode類所提供的getChildCount()方法取得目
前子節點的數量.
          */
         treeModel.insertNodeInto(node1, root, root.getChildCount());
         treeModel.insertNodeInto(node2, root, root.getChildCount());
         treeModel.insertNodeInto(node3, root, root.getChildCount());
         treeModel.insertNodeInto(node4, root, root.getChildCount());
       
         DefaultMutableTreeNode leafnode = new
                 DefaultMutableTreeNode("公司文件");

         //DefaultTreeModel類所提供的insertNodeInto()方法加入節點到父節點
的數量.
         treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
         leafnode = new DefaultMutableTreeNode("個人信件");
         treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
         leafnode = new DefaultMutableTreeNode("私人文件");
         treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
       
         leafnode = new DefaultMutableTreeNode("本機磁盤(C:)");
         treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
         leafnode = new DefaultMutableTreeNode("本機磁盤(D:)");
         treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
         leafnode = new DefaultMutableTreeNode("本機磁盤(E:)");
         treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
       
         DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("網站
列表");
         treeModel.insertNodeInto(node31, node3, node3.getChildCount());
         leafnode = new DefaultMutableTreeNode("奇摩站");
         treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
         leafnode = new DefaultMutableTreeNode("職棒消息");
         treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
         leafnode = new DefaultMutableTreeNode("網絡書店");
         treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
         try {
            LookAndFeel alloyLnF = new AlloyLookAndFeel();  
            UIManager.setLookAndFeel(alloyLnF);
         } catch (UnsupportedLookAndFeelException ex) {
         // You may handle the exception here
         }
          // this line needs to be implemented in order to make JWS work
properly
           UIManager.getLookAndFeelDefaults().put("ClassLoader",
getClass().getClassLoader());
       
         //以TreeModel建立JTree。
         JTree tree = new JTree(treeModel);
         /*改變JTree的外觀**/
           tree.putClientProperty("JTree.lineStyle","Horizontal");
         /*改變JTree的外觀**/
         JScrollPane scrollPane = new JScrollPane();
         scrollPane.setViewportView(tree);
       
         contentPane.add(scrollPane);
         f.pack();
         f.setVisible(true);
       
         f.addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent e) {
                 System.exit(0);
             }
         });

     }

     public static void main(String args[]) {
   
         new TreeDemo3();
     }
}
10-5:改變JTree的外觀:
  你可以使用JComponent所提供的putClientProperty(Object key,Object value)
方法來設置java預設的JTree外觀,設置方式共有
3種:
1.tree.putClientProperty("JTree.lineStyle","None"):java預設值。
2.tree.putClientProperty("JTree.lineStyle","Horizontal"):使JTree的文件夾
間具有水平分隔線。
3.tree.putClientProperty("JTree.lineStyle","Angled"):使JTree具有類似
Windows文件管理器的直角連接線。
   具體怎樣做,可看上例.

10-6:更換JTree節點圖案:
   JTree利用TreeCellRenderer界面來運行繪製節點的工作,同樣的,你不需要直
接支實作這個界面所定義的方法,因為java本身提
供一個已經實作好的類來給我們使用,此類就是DefaultTreeCellRenderer,你可以
在javax.swing.tree package中找到此類所提供
的方法。下面為使用DefaultTreeCellRenderer更改節點圖案的一個例子:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
import com.incors.plaf.alloy.*;

public class TreeDemo4{
    public TreeDemo4(){
      JFrame f=new JFrame("TreeDemo");
      Container contentPane=f.getContentPane();
    
         DefaultMutableTreeNode root = new DefaultMutableTreeNode("資源管
理器");
         DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("我的
公文包");
         DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的
電腦");
         DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夾");
         DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme");
         DefaultTreeModel treeModel = new DefaultTreeModel(root);
         treeModel.insertNodeInto(node1, root, root.getChildCount());
         treeModel.insertNodeInto(node2, root, root.getChildCount());
         treeModel.insertNodeInto(node3, root, root.getChildCount());
         treeModel.insertNodeInto(node4, root, root.getChildCount());
       
         DefaultMutableTreeNode leafnode = new
                 DefaultMutableTreeNode("公司文件");
         treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
         leafnode = new DefaultMutableTreeNode("個人信件");
         treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
         leafnode = new DefaultMutableTreeNode("私人文件");
         treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
       
         leafnode = new DefaultMutableTreeNode("本機磁盤(C:)");
         treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
         leafnode = new DefaultMutableTreeNode("本機磁盤(D:)");
         treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
         leafnode = new DefaultMutableTreeNode("本機磁盤(E:)");
         treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
       
         DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("網站
列表");
         treeModel.insertNodeInto(node31, node3, node3.getChildCount());
         leafnode = new DefaultMutableTreeNode("奇摩站");
         treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
         leafnode = new DefaultMutableTreeNode("職棒消息");
         treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
         leafnode = new DefaultMutableTreeNode("網絡書店");
         treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
         try {
            LookAndFeel alloyLnF = new AlloyLookAndFeel();  
            UIManager.setLookAndFeel(alloyLnF);
         } catch (UnsupportedLookAndFeelException ex) {
         // You may handle the exception here
         }
          // this line needs to be implemented in order to make JWS work
properly
           UIManager.getLookAndFeelDefaults().put("ClassLoader",
getClass().getClassLoader());

         JTree tree = new JTree(treeModel);
         tree.setRowHeight(20);
         DefaultTreeCellRenderer
cellRenderer=(DefaultTreeCellRenderer)tree.getCellRenderer();
         cellRenderer.setLeafIcon(new ImageIcon("..//icons//leaf.gif"));
         cellRenderer.setOpenIcon(new ImageIcon("..//icons//open.gif"));
         cellRenderer.setClosedIcon(new ImageIcon("..//icons//close.gif"));
       
         cellRenderer.setFont(new Font("宋體",Font.PLAIN,12));//設置字體.
         cellRenderer.setBackgroundNonSelectionColor(Color.white);
         cellRenderer.setBackgroundSelectionColor(Color.yellow);
         cellRenderer.setBorderSelectionColor(Color.red);
         /*設置選時或不選時,文字的變化顏色
          */
         cellRenderer.setTextNonSelectionColor(Color.black);
         cellRenderer.setTextSelectionColor(Color.blue);
       
         JScrollPane scrollPane=new JScrollPane();
         scrollPane.setViewportView(tree);
       
         contentPane.add(scrollPane);
         f.pack();
         f.setVisible(true);
       
         f.addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent e) {
                 System.exit(0);
             }
         });

     }

     public static void main(String args[]) {
   
         new TreeDemo4();
     }
}
  Window Xp界面:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
import com.incors.plaf.alloy.*;
public class TreeDemo3
{
     public TreeDemo3()
     {
        //設置成Alloy界面樣式
         try {
          
AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
            LookAndFeel alloyLnF = new AlloyLookAndFeel();
            JFrame.setDefaultLookAndFeelDecorated(true);
            UIManager.setLookAndFeel(alloyLnF);
         } catch (UnsupportedLookAndFeelException ex) {
         // You may handle the exception here
         }
          // this line needs to be implemented in order to make JWS work
properly
         UIManager.getLookAndFeelDefaults().put("ClassLoader",
getClass().getClassLoader());
         
          //JDialog.setDefaultLookAndFeelDecorated(true);
         JFrame f = new JFrame("firstTree");
      
         Container contentPane = f.getContentPane();
        // if (contentPane instanceof JComponent) {
         //   ((JComponent) contentPane).setMinimumSize(new
Dimension(100, 100));
         //}
        // Container contentPane = f.getContentPane();
       
       
         DefaultMutableTreeNode root = new DefaultMutableTreeNode("資源管
理器");
         DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("我的
公文包");
         DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的
電腦");
         DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夾");
         DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme");
       
         DefaultTreeModel treeModel = new DefaultTreeModel(root);
         treeModel.insertNodeInto(node1, root, root.getChildCount());
         treeModel.insertNodeInto(node2, root, root.getChildCount());
         treeModel.insertNodeInto(node3, root, root.getChildCount());
         treeModel.insertNodeInto(node4, root, root.getChildCount());
       
         DefaultMutableTreeNode leafnode = new
                 DefaultMutableTreeNode("公司文件");
         treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
         leafnode = new DefaultMutableTreeNode("個人信件");
         treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
         leafnode = new DefaultMutableTreeNode("私人文件");
         treeModel.insertNodeInto(leafnode, node1, node1.getChildCount());
       
         leafnode = new DefaultMutableTreeNode("本機磁盤(C:)");
         treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
         leafnode = new DefaultMutableTreeNode("本機磁盤(D:)");
         treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
         leafnode = new DefaultMutableTreeNode("本機磁盤(E:)");
         treeModel.insertNodeInto(leafnode, node2, node2.getChildCount());
       
         DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("網站
列表");
         treeModel.insertNodeInto(node31, node3, node3.getChildCount());
         leafnode = new DefaultMutableTreeNode("奇摩站");
         treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
         leafnode = new DefaultMutableTreeNode("職棒消息");
         treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());
         leafnode = new DefaultMutableTreeNode("網絡書店");
         treeModel.insertNodeInto(leafnode, node3, node3.getChildCount());

         JTree tree = new JTree(treeModel);
         /*改變JTree的外觀**/
         //  tree.putClientProperty("JTree.lineStyle","Horizontal");
         /*改變JTree的外觀**/
         JScrollPane scrollPane = new JScrollPane();
         scrollPane.setViewportView(tree);
       
         contentPane.add(scrollPane);
         f.pack();
         f.setVisible(true);
       
         f.addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent e) {
                 System.exit(0);
             }
         });

     }

     public static void main(String args[]) {
   
         new TreeDemo3();
     }
}


10-7:JTree的事件處理模式:
     在此節中,我們將詳細介紹JTree兩個常用的事件與處理,分別是
TreeModeEvent與TreeSelectionEvent.
10-7-1:處理TreeModeEvent事件:
   當樹的結構上有任何改變時,例如節點值改變了、新增節點、刪除節點等,都會
TreeModelEvent事件,要處理這樣的事件必須實
作TreeModelListener界面,此界面定義了4個方法,如下所示:
TreeModelListener方法:
Void              treeNodesChanged(TreeModelEvent e):當節點改變時系統就
會雲調用這個方法。
Void              treeNodesInserted(TreeModelEvent e):當新增節時系統就會
去調用這個方法。
Void              treeNodesRemoved(TreeModeEvent e):當刪除節點時系統就會
去調用這個方法。
Void              treeStructureChanged(TreeModelEvent e):當樹結構改變時
系統就會去調用這個方法。

   TreeModelEvent類本身提供了5個方法,幫我們取得事件的信息,如下所示:

TreeModelEvent方法:
int[]                getChildIndices():返回子節點群的索引值。
Object[]             getChildren():返回子節點群.
Object[]             getPath():返回Tree中一條path上(從root nod到leaf
node)的節點。
TreePath             getTreePath():取得目前位置的Tree Path.
String               toString():取得蝗字符串表示法.
 
     由TreeModelEvent的getTreePath()方法就可以得到TreePath對象,此對象就
能夠讓我們知道用戶目前正選哪一個節點,
TreePath類最常用的方法為:
      public  Object getLastPathComponent():取得最深(內)層的節點。
      public int    getPathCount():取得此path上共有幾個節點.
     我們來看下面這個例子,用戶可以在Tree上編輯節點,按下[Enter]鍵後就可
以改變原有的值,並將改變的值顯示在下面的
JLabel中:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.bedouin.*;

public class TreeDemo5 implements TreeModelListener
{
     JLabel label = null;
     String nodeName = null; //原有節點名稱
   
     public TreeDemo5()
     {
         try {
       
  AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
          AlloyTheme theme = new BedouinTheme();//設置界面的外觀,手冊中
共有5種樣式
          LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
             UIManager.setLookAndFeel(alloyLnF);
         } catch (UnsupportedLookAndFeelException ex) {
         // You may handle the exception here
         }
          // this line needs to be implemented in order to make JWS work
properly
         UIManager.getLookAndFeelDefaults().put("ClassLoader",
getClass().getClassLoader());
         JFrame f = new JFrame("TreeDemo");
         Container contentPane = f.getContentPane();
       
         DefaultMutableTreeNode root = new DefaultMutableTreeNode("資源管
理器");
         DefaultMutableTreeNode node1 = new DefaultMutableTreeNode("文件夾");
         DefaultMutableTreeNode node2 = new DefaultMutableTreeNode("我的
電腦");
         DefaultMutableTreeNode node3 = new DefaultMutableTreeNode("收藏夾");
         DefaultMutableTreeNode node4 = new DefaultMutableTreeNode("Readme");
         root.add(node1);
         root.add(node2);
         root.add(node3);
         root.add(node4);
       
         DefaultMutableTreeNode leafnode = new DefaultMutableTreeNode("公
司文件");
         node1.add(leafnode);
         leafnode = new DefaultMutableTreeNode("個人信件");
         node1.add(leafnode);
         leafnode = new DefaultMutableTreeNode("私人文件");
         node1.add(leafnode);
       
         leafnode = new DefaultMutableTreeNode("本機磁盤(C:)");
         node2.add(leafnode);
         leafnode = new DefaultMutableTreeNode("本機磁盤(D:)");
         node2.add(leafnode);
         leafnode = new DefaultMutableTreeNode("本機磁盤(E:)");
         node2.add(leafnode);
       
         DefaultMutableTreeNode node31 = new DefaultMutableTreeNode("網站
列表");
         node3.add(node31);
       
         leafnode = new DefaultMutableTreeNode("天勤網站");
         node31.add(leafnode);
         leafnode = new DefaultMutableTreeNode("足球消息");
         node31.add(leafnode);
         leafnode = new DefaultMutableTreeNode("網絡書店");
         node31.add(leafnode);
       
         JTree tree = new JTree(root);
         tree.setEditable(true);//設置JTree為可編輯的
         tree.addMouseListener(new MouseHandle());//使Tree加入檢測Mouse事
件,以便取得節點名稱
         //下面兩行取得DefaultTreeModel,並檢測是否有TreeModelEvent事件.
         DefaultTreeModel treeModel = (DefaultTreeModel)tree.getModel();
         treeModel.addTreeModelListener(this);
       
         JScrollPane scrollPane = new JScrollPane();
         scrollPane.setViewportView(tree);
       
         label = new JLabel("更改數據為: ");
         contentPane.add(scrollPane,BorderLayout.CENTER);
         contentPane.add(label,BorderLayout.SOUTH);
         f.pack();
         f.setVisible(true);
       
         f.addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent e) {
                 System.exit(0);
             }
         });

     }
     /*本方法實作TreeModelListener介面,本介面共定義四個方法,分別是
TreeNodesChanged()
      *treeNodesInserted()、treeNodesRemoved()、treeNodesRemoved()、
      *treeStructureChanged().在此範例中我們只針對更改節點值的部份,因此
只實作
      *treeNodesChanged()方法.
      */
     public void treeNodesChanged(TreeModelEvent e) {
       
         TreePath treePath = e.getTreePath();
         System.out.println(treePath);
         //下面這行由TreeModelEvent取得的DefaultMutableTreeNode為節點的父
節點,而不是用戶點選
         //的節點,這點讀者要特別注意。要取得真正的節點需要再加寫下面6行代碼.
         DefaultMutableTreeNode node =
(DefaultMutableTreeNode)treePath.getLastPathComponent();
         try {
             //getChildIndices()方法會返回目前修改節點的索引值。由於我們
只修改一個節點,因此節點索引值就放在index[0]
             //的位置,若點選的節點為root node,則getChildIndices()的返回
值為null,程式下面的第二行就在處理點選root
             //node產生的NullPointerException問題.
             int[] index = e.getChildIndices();
               //由DefaultMutableTreeNode類的getChildAt()方法取得修改的節
點對象.
             node = (DefaultMutableTreeNode)node.getChildAt(index[0]);
         } catch (NullPointerException exc) {}
         //由DefaultMutableTreeNode類getUserObject()方法取得節點的內容,
或是寫成node.toString()亦相同.
         label.setText(nodeName+"更改數據為: "+(String)node.getUserObject());
     }
     public void treeNodesInserted(TreeModelEvent e) {
     }
     public void treeNodesRemoved(TreeModelEvent e) {
     }
     public void treeStructureChanged(TreeModelEvent e) {
     }

     public static void main(String args[]) {
   
         new TreeDemo5();
     }
     //處理Mouse點選事件
     class MouseHandle extends MouseAdapter
     {
         public void mousePressed(MouseEvent e)
         {
             try{
               JTree tree = (JTree)e.getSource();
         //JTree的getRowForLocation()方法會返回節點的列索引值。例如本例
中,“本機磁盤(D:)”的列索引值為4,此索引值
         //會隨着其他數據夾的打開或收起而變支,但“資源管理器”的列索引值恆為0.
               int rowLocation = tree.getRowForLocation(e.getX(), e.getY());

              /*JTree的getPathForRow()方法會取得從root node到點選節點的一
條path,此path為一條直線,如程式運行的圖示
               *若你點選“本機磁盤(E:)”,則Tree Path為"資源管理器"-->"我的
電腦"-->"本機磁盤(E:)",因此利用TreePath
               *的getLastPathComponent()方法就可以取得所點選的節點.
               */

               TreePath treepath = tree.getPathForRow(rowLocation);
               TreeNode treenode = (TreeNode)
treepath.getLastPathComponent();
       
               nodeName = treenode.toString();
             }catch(NullPointerException ne){}
         }
     }
}

注:上面的程式MouseHandle中:
               int rowLocation = tree.getRowForLocation(e.getX(), e.getY());
               TreePath treepath = tree.getPathForRow(rowLocation);
    與:
               TreePath treepath=tree.getSelectionPath();
               等價,可互換。
 
   我們將“我的電腦”改成“網上領居”:
   我們再來看一個TreeModelEvent的例子,下面這個例子我們可以讓用戶自行增
加、刪除與修改節點:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.bedouin.*;

public class TreeDemo6 implements ActionListener,TreeModelListener{
   JLabel label=null;
   JTree  tree=null;
   DefaultTreeModel treeModel=null;
   String nodeName=null;//原有節點名稱
 
   public TreeDemo6(){
         try {
       
  AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
          AlloyTheme theme = new BedouinTheme();
          LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
             UIManager.setLookAndFeel(alloyLnF);
         } catch (UnsupportedLookAndFeelException ex) {
         // You may handle the exception here
         }
          // this line needs to be implemented in order to make JWS work
properly
         UIManager.getLookAndFeelDefaults().put("ClassLoader",
getClass().getClassLoader());
     JFrame f=new JFrame("TreeDemo6");
     Container contentPane=f.getContentPane();
   
     DefaultMutableTreeNode root=new DefaultMutableTreeNode("資源管理器");
   
     tree=new JTree(root);
     tree.setEditable(true);
     tree.addMouseListener(new MouseHandle());
     treeModel=(DefaultTreeModel)tree.getModel();
     treeModel.addTreeModelListener(this);
   
     JScrollPane scrollPane=new JScrollPane();
     scrollPane.setViewportView(tree);
   
     JPanel panel=new JPanel();
     JButton b=new JButton("新增節點");
     b.addActionListener(this);
     panel.add(b);
     b=new JButton("刪除節點");
     b.addActionListener(this);
     panel.add(b);
     b=new JButton("清除所有節點");
     b.addActionListener(this);
     panel.add(b);
   
     label=new JLabel("Action");
     contentPane.add(panel,BorderLayout.NORTH);
     contentPane.add(scrollPane,BorderLayout.CENTER);
     contentPane.add(label,BorderLayout.SOUTH);
     f.pack();
     f.setVisible(true);
     f.addWindowListener(new WindowAdapter(){
      public void windowClosing(WindowEvent e){
        System.exit(0);
      }
     });
   }
   //本方法運行新增、刪除、清除所有節點的程式代碼.
   public void actionPerformed(ActionEvent ae){
     if (ae.getActionCommand().equals("新增節點")){
       DefaultMutableTreeNode parentNode=null;
       DefaultMutableTreeNode newNode=new DefaultMutableTreeNode("新節點");
       newNode.setAllowsChildren(true);
       TreePath parentPath=tree.getSelectionPath();
         
          //取得新節點的父節點
     
parentNode=(DefaultMutableTreeNode)(parentPath.getLastPathComponent());

          //由DefaultTreeModel的insertNodeInto()方法增加新節點
     
treeModel.insertNodeInto(newNode,parentNode,parentNode.getChildCount());

          //tree的scrollPathToVisible()方法在使Tree會自動展開文件夾以便顯
示所加入的新節點。若沒加這行則加入的新節點
          //會被 包在文件夾中,你必須自行展開文件夾才看得到。
       tree.scrollPathToVisible(new TreePath(newNode.getPath()));    
       label.setText("新增節點成功");
     }
     if (ae.getActionCommand().equals("刪除節點")){
      TreePath treepath=tree.getSelectionPath();
      if (treepath!=null){
           //下面兩行取得選取節點的父節點.
        DefaultMutableTreeNode
selectionNode=(DefaultMutableTreeNode)treepath.getLastPathComponent();
        TreeNode parent=(TreeNode)selectionNode.getParent();
        if (parent!=null) {
              //由DefaultTreeModel的removeNodeFromParent()方法刪除節點,
包含它的子節點。
          treeModel.removeNodeFromParent(selectionNode);
          label.setText("刪除節點成功");
        }
      }    
     }
     if (ae.getActionCommand().equals("清除所有節點")){

         //下面一行,由DefaultTreeModel的getRoot()方法取得根節點.
      DefaultMutableTreeNode
rootNode=(DefaultMutableTreeNode)treeModel.getRoot();
 
         //下面一行刪除所有子節點.
      rootNode.removeAllChildren(); 
 
         //刪除完後務必運行DefaultTreeModel的reload()操作,整個Tree的節點
才會真正被刪除.   
      treeModel.reload();
      label.setText("清除所有節點成功");
     }
   }
      public void treeNodesChanged(TreeModelEvent e){
       TreePath treePath=e.getTreePath();
       DefaultMutableTreeNode
node=(DefaultMutableTreeNode)treePath.getLastPathComponent();
       try{
         int[] index=e.getChildIndices();
         node=(DefaultMutableTreeNode)node.getChildAt(index[0]);
       }catch(NullPointerException exc){}
         label.setText(nodeName+"更改數據為:"+(String)node.getUserObject());
      }
     public void treeNodesInserted(TreeModelEvent e){
       System.out.println("new node insered");      
     }
     public void treeNodesRemoved(TreeModelEvent e){
       System.out.println("node deleted");
     }
     public void treeStructureChanged(TreeModelEvent e){
       System.out.println("Structrue changed");
     }
     public static void main(String[] args){
       new TreeDemo6();
     }
   
     class MouseHandle extends MouseAdapter{
       public void mousePressed(MouseEvent e){
          try{
            JTree tree=(JTree)e.getSource();
            int rowLocation=tree.getRowForLocation(e.getX(),e.getY());
            TreePath treepath=tree.getPathForRow(rowLocation);
            TreeNode treenode=(TreeNode)treepath.getLastPathComponent();
            nodeName=treenode.toString();         
          }catch(NullPointerException ne){}
       }
     }
}
 
10-7-2:處理TreeSelectionEvent事件:
     當我們在JTree上點選任何一個節點,都會觸發TreeSelectionEvent事件,如
果我們要處理這樣的事件,必須實作
TreeSelectionListener界面,此界面只定義了一個方法,那就是valueChanged()
方法。
     TreeSelectionEvent最常用在處理顯示節點的內容,例如你在文件圖標中點兩
下就可以看到文件的內容。在JTree中選擇節點
的方式共有3種,這3種情況跟選擇JList上的項目是一模一樣的,分別是:
       DISCONTIGUOUS_TREE_SELECTION:可作單一選擇,連續點選擇(按住[Shift]
鍵),不連續選擇多個節點(按住[Ctrl]鍵),
這是java預設值.
       CONTINUOUS_TREE_SELECTION:按住[Shift]鍵,可對某一連續的節點區間作
選取。
       SINGLE_TREE_SELECTION:一次只能選一個節點。
    你可以自行實作TreeSelectionModel製作作更複雜的選擇方式,但通常是沒有
必要的,因為java提供了預設的選擇模式類供我們
使用,那就是DefaultTreeSelectionModel,利用這個類我們可以很方便的設置上面
3種選擇模式。
    下面這個範例,當用戶點選了一個文件名時,就會將文件的內容顯示出來。
TreeDemo7.java

import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import com.incors.plaf.alloy.*;
import com.incors.plaf.alloy.themes.glass.*;

public class TreeDemo7 implements TreeSelectionListener
{
     JEditorPane editorPane;

     public TreeDemo7()
     {
         JFrame f = new JFrame("TreeDemo");
         Container contentPane = f.getContentPane();
         DefaultMutableTreeNode root = new DefaultMutableTreeNode("資源管
理器");
         DefaultMutableTreeNode node = new
DefaultMutableTreeNode("TreeDemo1.java");
         root.add(node);
         node = new DefaultMutableTreeNode("TreeDemo2.java");
         root.add(node);
         node = new DefaultMutableTreeNode("TreeDemo3.java");
         root.add(node);
         node = new DefaultMutableTreeNode("TreeDemo4.java");
         root.add(node);
       
         JTree tree = new JTree(root);
         //設置Tree的選擇模式為一次只能選擇一個節點
       
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
         //檢查是否有TreeSelectionEvent事件。
         tree.addTreeSelectionListener(this);

         //下面五行,JSplitPane中,左邊是放含有JTree的JScrollPane,右邊是
放JEditorPane.
         JScrollPane scrollPane1 = new JScrollPane(tree);
         editorPane = new JEditorPane();
         JScrollPane scrollPane2 = new JScrollPane(editorPane);
         JSplitPane splitPane = new JSplitPane(
         JSplitPane.HORIZONTAL_SPLIT,true, scrollPane1, scrollPane2);

         contentPane.add(splitPane);
         f.pack();
         f.setVisible(true);
       
         f.addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent e) {
                 System.exit(0);
             }
         });
     }
     //本方法實作valueChanged()方法
     public void valueChanged(TreeSelectionEvent e)
     {
         JTree tree = (JTree) e.getSource();
         //利用JTree的getLastSelectedPathComponent()方法取得目前選取的節點.
         DefaultMutableTreeNode selectionNode =
             (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();

         String nodeName = selectionNode.toString();
       
         //判斷是否為樹葉節點,若是則顯示文件內容,若不是則不做任何事。
         if (selectionNode.isLeaf())
         {
            /*取得文件的位置路徑,System.getProperty("user.dir")可以取得目
前工作的路徑,
             *System.getProperty("file.separator")是取得文件分隔符,例如
在window環境的
             *文件分陋符是"/",而Unix環境的文件分隔符剛好相反,是"/".利用
System.getProperty()
             *方法你可以取得下列的信息:
             java.version                             顯示java版本
             java.endor                               顯示java製造商
             java.endor.url                           顯示java製造商URL
             java.home                                顯示java的安裝路徑
             java.class.version                       顯示java類版本
             java.class.path                          顯示java classpath
             os.name                                  顯示操作系統名稱
             os.arch                                  顯示操作系統結構,如x86
             os.version                               顯示操作系統版本
             file.separator                           取得文件分隔符
             path.separator                           取得路徑分隔符,如
Unix是以“:”表示
             line.separator                           取得換行符號,如
Unix是以"/n"表示
             user.name                                取得用戶名稱
             user.home                                取得用戶家目錄(home
directory),如Windows中Administrator的家目
                                                      錄為c:/Documents
and Settings/Administrator
             user.dir                                 取得用戶目前的工作目錄.
             */
             String filepath = "file:"+System.getProperty("user.dir") +
                                System.getProperty("file.separator") +
                                nodeName;
                          
             try {
                //利用JEditorPane的setPage()方法將文件內容顯示在
editorPane中。若文件路徑錯誤,則會產生IOException.
                  editorPane.setPage(filepath);
             } catch(IOException ex) {
                  System.out.println("找不到此文件");
             }
         }
     }
   
     public static void main(String[] args) {
      SwingUtil.setLookAndFeel();
         new TreeDemo7();      
     }
}            

class SwingUtil{
   public static final void setLookAndFeel() {
    try{
             Font font = new Font("JFrame", Font.PLAIN, 12);
             Enumeration keys = UIManager.getLookAndFeelDefaults().keys();
 
             while (keys.hasMoreElements()) {
                Object key = keys.nextElement();
                if (UIManager.get(key) instanceof Font) {
                   UIManager.put(key, font);
                 }
             }
       
  AlloyLookAndFeel.setProperty("alloy.isLookAndFeelFrameDecoration", "true");
          AlloyTheme theme = new GlassTheme();
          LookAndFeel alloyLnF = new AlloyLookAndFeel(theme);
            JFrame.setDefaultLookAndFeelDecorated(true);
         
            UIManager.setLookAndFeel(alloyLnF);
    }catch(UnsupportedLookAndFeelException ex){
      ex.printStackTrace();
    }
  }
}

10-8:JTree的其他操作:
      我們在之前小節中曾說到Tree中的每一個節點都是一個TreeNode,並可利用
JTree的setEditable()方法設置節點是否可編輯,
若要在Tree中找尋節點的父節點或子節點,或判斷是否為樹節點,皆可由實作
TreeNode界面做到,但要編輯節點呢?java將編輯
節點的任務交給TreeCellEditor,TreeCellEditor本身是一個界面,裡面只定義了
getTreeCellEditor Component()方法,你可以實
作此方法使節點具有編輯的效果。不過你不用這麼辛苦去實作這個方法,java本身
提供了DefaultTreeCellEditor類來實作此方法
,亦提供了其他許多方法,例如取得節點內容(getCellEditorValue()) 、設置節
點字體(setFont())、決定節點是否可編輯
(isCellEditable())等等。除非你覺得DefaultTreeCellEditor所提供的功能不
夠,你才需要去實作TreeCellEditor界面。你可以利
用JTree的getCellEditor()方法取得DefaultTreeCellEditor對象。當我們編輯節
點時會觸發ChangeEvent事件,你可以實作
CellEditorListener界面來處理此事件,CellEditorListener界面包括兩個方法,
分別是editingStopped(ChangeEvent e)與
editingCanceled(ChangeEvent e).若你沒有實作TreeCellEditor界面,系統會以
預設的DefaultTreeCellEdtior類來處理掉這兩個
方法(你可以在DefaultTreeCellEditor中找到這兩個方法),因此你無須再編寫任
何的程式。
      另外,JTree還有一種事件處理模式,那就是TreeExpansionEvent事件。要處
理這個事件你必須實作TreeExpansionListener
界面,此界面定義了兩個方法,分別是treeCollapsed(TreeExpansionEvent e)與
treeExpanded(TreeExpansionEvent e).當節點展
開時系統就會自動調用treeExpanded()方法,當節點合起來時,系統就會自動調用
treeCollapsed()方法。你可以在這兩個方法中編寫所要處理事情的程式碼。

你可能感兴趣的:(java,swing,ClassLoader,object,tree,import)