JAVA SWING JTree全面了解

基础了解

使用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()方法。你可以在這兩個方法中編寫所要處理事情的程式碼。

 JTree行滚动到可视图区域有专门的方法如下:

JTree.scrollPathToVisible(TreePath path) ---

 

scrollPathToVisible(TreePath path) 
          确保路径中所有的路径组件均展开(最后一个路径组件除外)并滚动,以便显示该路径标识的节点。

TreePath获得方法:

1.JTree.LeadSelectionPath()

2.JTreegetPathForLocation(int x, int y)

3.JTree.getPathForRow(int row)
4.DefaultMutableTreeNode.getPath() //返回从根到达此节点的路径 TreeNode[]

TreePath(Object[] path)//可构造出TreePath对象,传入参数TreeNode[].

树节点展开方法:这是一个保护方法,需要继承树才能重写

protected  voidsetExpandedState(TreePath path, boolean state)
          设置此 JTree 的展开状态。

setExpandedState

protected void setExpandedState(TreePath path,
                                boolean state)
设置此 JTree 的展开状态。 如果 state 为 true,则 path 的所有父路径和路径都被标记为展开。如果 state 为 false,则 path 的所有父路径被标记为展开,但是 path 本身被标记为折叠。

如果 TreeWillExpandListener 禁止它,则会失败。

 

 

 voidcollapsePath(TreePath path)
          确保指定路径标识的节点是折叠的,并且可查看。
 voidcollapseRow(int row)
          确保指定行中的节点是折叠的。

collapsePath
public void collapsePath(TreePath path)
确保指定路径标识的节点是折叠的,并且可查看。

参数:
path - 标识节点的 TreePath
collapseRow
public void collapseRow(int row)
确保指定行中的节点是折叠的。

如果 row < 0 或 >= getRowCount,则此方法无效。

参数:
row - 指定一个显示行的整数,其中 0 表示显示的第一行

 

JTREE展开(不展开子节点)

方法1:protected void setExpandedState(TreePath path, boolean state)--树节点展开方法:这是一个保护方法,需要继承树才能重写.待测试.

public class JTreeEx extends JTree
{
 private static final long serialVersionUID = 1L;

 public JTreeEx(TreeModel newModel)
 {
  super(newModel);
 }

 @Override
 public void setExpandedState(TreePath path, boolean state)
 {
  super.setExpandedState(path, state);
  
 }

}

 

for (int i = 0; i < tree.getRowCount(); i++)
    {

     TreePath tp = tree.getPathForRow(i);
     DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent();

     if ("country1".equals(node.getUserObject().toString()))
     {
      // tree.setExpandedState(tp, false);--此方法不好使.后续有时间再测试,现用下面的方法实现.
      tree.expandPath(tp);//先展开,
      Enumeration<?> enums = node.children();
      while (enums.hasMoreElements())
      {
       DefaultMutableTreeNode dtn = (DefaultMutableTreeNode) enums.nextElement();

       TreePath tp1 = tp.pathByAddingChild(dtn);
       tree.collapsePath(tp1);//后收缩
       System.out.println("expande tp1:" + tp1);

      }

     }
    }

   }

 

 

方法2:先展开后收缩.

即public void collapsePath(TreePath path)--会展开此路径的所有父节点和子节点

public void expandPath(TreePath path)---收缩所有子节点.

 

Swing拓展JTree功能--仿QQ树

相信读者都清楚树在图形界面的重要性,但JAVA自带的JTree功能狭窄,运用起来非常的不方便,不灵活,比如在已经添加的节点中不能更改其文本信息和图片信息,而且所有的叶子节点的图片都是通过DefaultTreeCellRenderer的方法setLeafIcon()来实现的,所以全部的叶子节点的图片都是一样,这点在实际的软件开发中是一个致命的漏洞,比如腾讯QQ 的好友就是一棵树,总不可能全部好友的头像都一样吧,为此,笔者将通过自己的经验重写DefaultTreeCellRenderer类,让我们在开发中更灵活的运用树的组件。

要重写DefaultTreeCellRenderer,又要不失去它本身的功能,唯一的办法就是继承它,拓展它的方法,不仅要继承该类,我们还要继承DefaultMutableTreeNode类,使我们的节点更加丰富
 
下面笔者将创建类IconNodeRenderer继承类DefaultTreeCellRenderer
                    创建类IconNode继承DefaultMutableTreeNode
 
为了更方便的使用我们自定义的树,笔者将这两个类封装在一个文件里,便于管理

package tree.imagetree;

 

import java.awt.Component;

 

import javax.swing.Icon;

import javax.swing.JTree;

import javax.swing.tree.DefaultMutableTreeNode;

import javax.swing.tree.DefaultTreeCellRenderer;

 

publicclass IconNodeRendererextends DefaultTreeCellRenderer//继承该类

{

    //重写该方法

    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);//调用父类的该方法

       Icon icon = ((IconNode) value).getIcon();//从节点读取图片

       String txt = ((IconNode) value).getText();//从节点读取文本

       setIcon(icon);//设置图片

       setText(txt);//设置文本

       returnthis;

    }

}

 

// 定义节点类

class IconNodeextends DefaultMutableTreeNode

{

    protected Iconicon;

    protected Stringtxt;

 

    //只包含文本的节点构造

    public IconNode(String txt)

    {

       super();

       this.txt = txt;

    }

 

    //包含文本和图片的节点构造

    public IconNode(Icon icon, String txt)

    {

       super();

       this.icon = icon;

       this.txt = txt;

    }

 

    publicvoid setIcon(Icon icon)

    {

       this.icon = icon;

    }

 

    public Icon getIcon()

    {

       returnicon;

    }

 

    publicvoid setText(String txt)

    {

       this.txt = txt;

    }

 

    public String getText()

    {

       returntxt;

    }

}

 

package tree.imagetree;

 

import java.awt.BorderLayout;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

 

import javax.swing.ImageIcon;

import javax.swing.JFrame;

import javax.swing.JScrollPane;

import javax.swing.JTree;

import javax.swing.SwingUtilities;

import javax.swing.UIManager;

import javax.swing.tree.DefaultTreeCellRenderer;

import javax.swing.tree.TreePath;

 

publicclass ImageTreeDemo

{

    JFrame frame;

 

    public ImageTreeDemo()

    {

       try

       {

           UIManager.setLookAndFeel("com.jtattoo.plaf.bernstein.BernsteinLookAndFeel");

           SwingUtilities.updateComponentTreeUI(frame);

       } catch (Exception e)

       {

       }

 

       frame =new JFrame("");

       frame.setSize(150, 300);

       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

 

       IconNode root1 = new IconNode(new ImageIcon("3.png"),"高中同学");

       IconNode root2 = new IconNode(new ImageIcon("3.png"),"初中同学");

 

       root1.add(new IconNode(new ImageIcon("5.png"),"雅君"));

       root1.add(new IconNode(new ImageIcon("1.png"),"伟旭"));

       root1.add(new IconNode(new ImageIcon("2.png"),"宜群"));

       root2.add(new IconNode(new ImageIcon("2.png"),"彬强"));

       root2.add(new IconNode(new ImageIcon("1.png"),"小强"));

 

       IconNode Root = new IconNode(null,null);//定义根节点

       Root.add(root1);//定义二级节点

       Root.add(root2);//定义二级节点

 

       final JTree tree =new JTree(Root);//定义树

       tree.setCellRenderer(new IconNodeRenderer());//设置单元格描述

       tree.setEditable(false);//设置树是否可编辑

       tree.setRootVisible(false);//设置树的根节点是否可视

       tree.setToggleClickCount(1);//设置单击几次展开数节点

 

       DefaultTreeCellRenderer cellRenderer = (DefaultTreeCellRenderer) tree.getCellRenderer();//获取该树的Renderer

       cellRenderer.setClosedIcon(new ImageIcon("2.gif"));//关闭打开图标

       cellRenderer.setOpenIcon(new ImageIcon("2.gif"));//设置展开图标

 

       //测试事件

       tree.addMouseListener(new MouseAdapter()

       {

           publicvoid mouseClicked(MouseEvent e)

           {

              if (e.getClickCount() == 2)//双击节点

              {

                  TreePath path = tree.getSelectionPath();//获取选中节点路径

                  IconNode node = (IconNode) path.getLastPathComponent();//通过路径将指针指向该节点

                  if (node.isLeaf())//如果该节点是叶子节点

                  {

                     // DefaultTreeModel

                     // model=(DefaultTreeModel)tree.getModel();//获取该树的模型

                     // model.removeNodeFromParent(node);//从本树删除该节点

                      node.setIcon(new ImageIcon("3.png"));//修改该节点的图片

                     node.setText("双击");//修改该节点的文本

                     tree.repaint();//重绘更新树

                     System.out.println(node.getText());

                  } else

                  //不是叶子节点

                  {

                  }

 

              }

           }

       });

 

       JScrollPane sp = new JScrollPane(tree);

       frame.getContentPane().add(sp, BorderLayout.CENTER);

       frame.setVisible(true);

    }

 

    publicstaticvoid main(String[] args)

    {

       new ImageTreeDemo();

    }

}

 

普通选择树实例

在使用Java Swing开发UI程序时,很有可能会遇到使用带复选框的树的需求,但是Java Swing并没有提供这个组件,因此如果你有这个需求,你就得自己动手实现带复选框的树。

CheckBoxTree与JTree在两个层面上存在差异:

  1. 在模型层上,CheckBoxTree的每个结点需要一个成员来保存其是否被选中,但是JTree的结点则不需要。
  2. 在视图层上,CheckBoxTree的每个结点比JTree的结点多显示一个复选框。
既然存在两个差异,那么只要我们把这两个差异部分通过自己的实现填补上,那么带复选框的树也就实现了。
现在开始解决第一个差异。为了解决第一个差异,需要定义一个新的结点类CheckBoxTreeNode,该类继承DefaultMutableTreeNode,并增加新的成员isSelected来表示该结点是否被选中。对于一颗CheckBoxTree,如果某一个结点被选中的话,其复选框会勾选上,并且使用CheckBoxTree的动机在于可以一次性地选中一颗子树。那么,在选中或取消一个结点时,其祖先结点和子孙结点应该做出某种变化。在此,我们应用如下递归规则:
  1. 如果某个结点被手动选中,那么它的所有子孙结点都应该被选中;如果选中该结点使其父节点的所有子结点都被选中,则选中其父结点。
  2. 如果某个结点被手动取消选中,那么它的所有子孙结点都应该被取消选中;如果该结点的父结点处于选中状态,则取消选中其父结点。
注意:上面的两条规则是递归规则,当某个结点发生变化,导致另外的结点发生变化时,另外的结点也会导致其他的结点发生变化。在上面两条规则中,强调手动,是因为手动选中或者手动取消选中一个结点,会导致其他结点发生非手动的选中或者取消选中,这种非手动导致的选中或者非取消选中则不适用于上述规则。

 

package tree.checktree;

 

import java.awt.Color;

import java.awt.Component;

import java.awt.Dimension;

 

import javax.swing.JCheckBox;

import javax.swing.JPanel;

import javax.swing.JTree;

import javax.swing.UIManager;

import javax.swing.plaf.ColorUIResource;

import javax.swing.tree.TreeCellRenderer;

 

public class CheckBoxTreeCellRenderer extends JPanel implements TreeCellRenderer

{

       private static final long serialVersionUID = 1L;

       protected JCheckBox check;

       protected CheckBoxTreeLabel label;

      

       public CheckBoxTreeCellRenderer()

       {

              setLayout(null);

              add(check = new JCheckBox());

              add(label = new CheckBoxTreeLabel());

              check.setBackground(UIManager.getColor("Tree.textBackground"));

              label.setForeground(UIManager.getColor("Tree.textForeground"));

       }

      

       /**

        * 返回的是一个<code>JPanel</code>对象,该对象中包含一个<code>JCheckBox</code>对象

        * 和一个<code>JLabel</code>对象。并且根据每个结点是否被选中来决定<code>JCheckBox</code>

        * 是否被选中。

        */

       //@Override

       public Component getTreeCellRendererComponent(JTree tree, Object value,

                     boolean selected, boolean expanded, boolean leaf, int row,

                     boolean hasFocus)

       {

              String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, hasFocus);

              setEnabled(tree.isEnabled());

              check.setSelected(((CheckBoxTreeNode)value).isSelected());

              label.setFont(tree.getFont());

              label.setText(stringValue);

              label.setSelected(selected);

              label.setFocus(hasFocus);

              if(leaf)

                     label.setIcon(UIManager.getIcon("Tree.leafIcon"));

              else if(expanded)

                     label.setIcon(UIManager.getIcon("Tree.openIcon"));

              else

                     label.setIcon(UIManager.getIcon("Tree.closedIcon"));

                    

              return this;

       }

 

       @Override

       public Dimension getPreferredSize()

       {

              Dimension dCheck = check.getPreferredSize();

              Dimension dLabel = label.getPreferredSize();

              return new Dimension(dCheck.width + dLabel.width, dCheck.height < dLabel.height ? dLabel.height: dCheck.height);

       }

      

       @Override

       public void doLayout()

       {

              Dimension dCheck = check.getPreferredSize();

              Dimension dLabel = label.getPreferredSize();

              int yCheck = 0;

              int yLabel = 0;

              if(dCheck.height < dLabel.height)

                     yCheck = (dLabel.height - dCheck.height) / 2;

              else

                     yLabel = (dCheck.height - dLabel.height) / 2;

              check.setLocation(0, yCheck);

              check.setBounds(0, yCheck, dCheck.width, dCheck.height);

              label.setLocation(dCheck.width, yLabel);

              label.setBounds(dCheck.width, yLabel, dLabel.width, dLabel.height);

       }

      

       @Override

       public void setBackground(Color color)

       {

              if(color instanceof ColorUIResource)

                     color = null;

              super.setBackground(color);

       }

      

}

 

package tree.checktree;

 

import java.awt.Color;

import java.awt.Dimension;

import java.awt.Graphics;

 

import javax.swing.Icon;

import javax.swing.JLabel;

import javax.swing.UIManager;

import javax.swing.plaf.ColorUIResource;

 

public class CheckBoxTreeLabel extends JLabel

{

       private static final long serialVersionUID = 1L;

       private boolean isSelected;

       private boolean hasFocus;

      

       public CheckBoxTreeLabel()

       {

       }

      

       @Override

       public void setBackground(Color color)

       {

              if(color instanceof ColorUIResource)

                     color = null;

              super.setBackground(color);

       }

      

       @Override

       public void paint(Graphics g)

       {

              String str;

              if((str = getText()) != null)

              {

                     if(0 < str.length())

                     {

                            if(isSelected)

                                   g.setColor(UIManager.getColor("Tree.selectionBackground"));

                            else

                                   g.setColor(UIManager.getColor("Tree.textBackground"));

                            Dimension d = getPreferredSize();

                            int imageOffset = 0;

                            Icon currentIcon = getIcon();

                            if(currentIcon != null)

                                   imageOffset = currentIcon.getIconWidth() + Math.max(0, getIconTextGap() - 1);

                            g.fillRect(imageOffset, 0, d.width - 1 - imageOffset, d.height);

                            if(hasFocus)

                            {

                                   g.setColor(UIManager.getColor("Tree.selectionBorderColor"));

                                   g.drawRect(imageOffset, 0, d.width - 1 - imageOffset, d.height - 1);

                            }

                     }

              }

              super.paint(g);

       }

      

       @Override

       public Dimension getPreferredSize()

       {

              Dimension retDimension = super.getPreferredSize();

              if(retDimension != null)

                     retDimension = new Dimension(retDimension.width + 3, retDimension.height);

              return retDimension;

       }

      

       public void setSelected(boolean isSelected)

       {

              this.isSelected = isSelected;

       }

      

       public void setFocus(boolean hasFocus)

       {

              this.hasFocus = hasFocus;

       }

}

 

package tree.checktree;

 

import javax.swing.tree.DefaultMutableTreeNode;

 

publicclass CheckBoxTreeNodeextends DefaultMutableTreeNode

{

 

    privatestaticfinallongserialVersionUID = 1L;

    protectedbooleanisSelected;

 

    public CheckBoxTreeNode()

    {

       this(null);

    }

 

    public CheckBoxTreeNode(Object userObject)

    {

       this(userObject,true,false);

    }

 

    public CheckBoxTreeNode(Object userObject,boolean allowsChildren,

           boolean isSelected)

    {

       super(userObject, allowsChildren);

       this.isSelected = isSelected;

    }

 

    publicboolean isSelected()

    {

       returnisSelected;

    }

 

    publicvoid setSelected(boolean _isSelected)

    {

       this.isSelected = _isSelected;

 

       if (_isSelected)

       {

           //如果选中,则将其所有的子结点都选中

           if (children !=null)

           {

              for (Object obj :children)

              {

                  CheckBoxTreeNode node = (CheckBoxTreeNode) obj;

                  if (_isSelected != node.isSelected())

                     node.setSelected(_isSelected);

              }

           }

           //向上检查,如果父结点的所有子结点都被选中,那么将父结点也选中

           CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;

           //开始检查pNode的所有子节点是否都被选中

           if (pNode !=null)

           {

              int index = 0;

              for (; index < pNode.children.size(); ++index)

              {

                  CheckBoxTreeNode pChildNode = (CheckBoxTreeNode) pNode.children

                         .get(index);

                  if (!pChildNode.isSelected())

                     break;

              }

              /*

               * 表明pNode所有子结点都已经选中,则选中父结点,该方法是一个递归方法,因此在此不需要进行迭代,因为

               * 当选中父结点后,父结点本身会向上检查的。

               */

              if (index == pNode.children.size())

              {

                  if (pNode.isSelected() != _isSelected)

                     pNode.setSelected(_isSelected);

              }

           }

       } else

       {

           /*

            * 如果是取消父结点导致子结点取消,那么此时所有的子结点都应该是选择上的;

            * 否则就是子结点取消导致父结点取消,然后父结点取消导致需要取消子结点,但是这时候是不需要取消子结点的。

            */

           if (children !=null)

           {

              int index = 0;

              for (; index <children.size(); ++index)

              {

                  CheckBoxTreeNode childNode = (CheckBoxTreeNode)children

                         .get(index);

                  if (!childNode.isSelected())

                     break;

              }

              //从上向下取消的时候

              if (index ==children.size())

              {

                  for (int i = 0; i <children.size(); ++i)

                  {

                     CheckBoxTreeNode node = (CheckBoxTreeNode)children

                            .get(i);

                     if (node.isSelected() != _isSelected)

                         node.setSelected(_isSelected);

                  }

              }

           }

 

           //向上取消,只要存在一个子节点不是选上的,那么父节点就不应该被选上。

           CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;

           if (pNode !=null && pNode.isSelected() != _isSelected)

              pNode.setSelected(_isSelected);

       }

    }

}

 

package tree.checktree;

 

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

 

import javax.swing.JTree;

import javax.swing.tree.TreePath;

import javax.swing.tree.DefaultTreeModel;

 

public class CheckBoxTreeNodeSelectionListener extends MouseAdapter

{

       @Override

       public void mouseClicked(MouseEvent event)

       {

              JTree tree = (JTree)event.getSource();

              int x = event.getX();

              int y = event.getY();

              int row = tree.getRowForLocation(x, y);

              TreePath path = tree.getPathForRow(row);

              if(path != null)

              {

                     CheckBoxTreeNode node = (CheckBoxTreeNode)path.getLastPathComponent();

                     if(node != null)

                     {

                            boolean isSelected = !node.isSelected();

                            node.setSelected(isSelected);

                            ((DefaultTreeModel)tree.getModel()).nodeStructureChanged(node);

                     }

              }

       }

}

 

package tree.checktree;

 

import javax.swing.JFrame;

import javax.swing.JScrollPane;

import javax.swing.JTree;

import javax.swing.UIManager;

import javax.swing.UnsupportedLookAndFeelException;

import javax.swing.tree.DefaultTreeModel;

//http://www.jroller.com/resources/s/santhosh/TristateCheckBox.java

public class CheckBoxTreeDemo

{

       public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException

       {

              UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

              JFrame frame = new JFrame("CheckBoxTreeDemo");

              frame.setBounds(200, 200, 400, 400);

              JTree tree = new JTree();

              CheckBoxTreeNode rootNode = new CheckBoxTreeNode("root");

              CheckBoxTreeNode node1 = new CheckBoxTreeNode("node_1");

              CheckBoxTreeNode node1_1 = new CheckBoxTreeNode("node_1_1");

              CheckBoxTreeNode node1_2 = new CheckBoxTreeNode("node_1_2");

              CheckBoxTreeNode node1_3 = new CheckBoxTreeNode("node_1_3");

              node1.add(node1_1);

              node1.add(node1_2);

              node1.add(node1_3);

              CheckBoxTreeNode node2 = new CheckBoxTreeNode("node_2");

              CheckBoxTreeNode node2_1 = new CheckBoxTreeNode("node_2_1");

              CheckBoxTreeNode node2_2 = new CheckBoxTreeNode("node_2_2");

              node2.add(node2_1);

              node2.add(node2_2);

              rootNode.add(node1);

              rootNode.add(node2);

              DefaultTreeModel model = new DefaultTreeModel(rootNode);

              tree.addMouseListener(new CheckBoxTreeNodeSelectionListener());

              tree.setModel(model);

              tree.setCellRenderer(new CheckBoxTreeCellRenderer());

              JScrollPane scroll = new JScrollPane(tree);

              scroll.setBounds(0, 0, 300, 320);

              frame.getContentPane().add(scroll);

             

              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

              frame.setVisible(true);

       }

}

 

三态选择树实例一

package tree.threetree;

 

import java.awt.BorderLayout;

import java.awt.Component;

 

import javax.swing.JPanel;

import javax.swing.JTree;

import javax.swing.tree.TreeCellRenderer;

import javax.swing.tree.TreePath;

 

public class CheckTreeCellRenderer extends JPanel implements TreeCellRenderer

{

       private static final long serialVersionUID = 1L;

       private CheckTreeSelectionModel selectionModel;

       private TreeCellRenderer delegate;

       private TristateCheckBox checkBox = new TristateCheckBox();

 

       public CheckTreeCellRenderer(TreeCellRenderer delegate,

                     CheckTreeSelectionModel selectionModel)

       {

              this.delegate = delegate;

              this.selectionModel = selectionModel;

              setLayout(new BorderLayout());

              setOpaque(false);

              checkBox.setOpaque(false);

       }

 

       public Component getTreeCellRendererComponent(JTree tree, Object value,

                     boolean selected, boolean expanded, boolean leaf, int row,

                     boolean hasFocus)

       {

              Component renderer = delegate.getTreeCellRendererComponent(tree, value,

                            selected, expanded, leaf, row, hasFocus);

 

              TreePath path = tree.getPathForRow(row);

              if (path != null)

              {

                     if (selectionModel.isPathSelected(path, true))

                            checkBox.setState(TristateCheckBox.SELECTED); // Boolean.TRUE

                     else

                            checkBox

                                          .setState(selectionModel.isPartiallySelected(path) ? TristateCheckBox.DONT_CARE

                                                        : TristateCheckBox.NOT_SELECTED);

                     // checkBox.setState(selectionModel.isPartiallySelected(path) ? null

                     // : Boolean.FALSE);

              }

              removeAll();

              add(checkBox, BorderLayout.WEST);

              add(renderer, BorderLayout.CENTER);

              return this;

       }

}

 

package tree.threetree;

 

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

 

import javax.swing.JCheckBox;

import javax.swing.JTree;

import javax.swing.event.TreeSelectionEvent;

import javax.swing.event.TreeSelectionListener;

import javax.swing.tree.TreePath;

 

public class CheckTreeManager extends MouseAdapter implements

              TreeSelectionListener

{

       private CheckTreeSelectionModel selectionModel;

       private JTree tree = new JTree();

       int hotspot = new JCheckBox().getPreferredSize().width;

 

       public CheckTreeManager(JTree tree)

       {

              this.tree = tree;

              selectionModel = new CheckTreeSelectionModel(tree.getModel());

              tree.setCellRenderer(new CheckTreeCellRenderer(tree.getCellRenderer(),

                            selectionModel));

              tree.addMouseListener(this);

              selectionModel.addTreeSelectionListener(this);

       }

 

       public void mouseClicked(MouseEvent me)

       {

              TreePath path = tree.getPathForLocation(me.getX(), me.getY());

              if (path == null)

                     return;

              if (me.getX() > tree.getPathBounds(path).x + hotspot)

                     return;

 

              boolean selected = selectionModel.isPathSelected(path, true);

              selectionModel.removeTreeSelectionListener(this);

 

              try

              {

                     if (selected)

                            selectionModel.removeSelectionPath(path);

                     else

                            selectionModel.addSelectionPath(path);

              } finally

              {

                     selectionModel.addTreeSelectionListener(this);

                     tree.treeDidChange();

              }

       }

 

       public CheckTreeSelectionModel getSelectionModel()

       {

              return selectionModel;

       }

 

       public void valueChanged(TreeSelectionEvent e)

       {

              tree.treeDidChange();

       }

}

 

package tree.threetree;

 

import java.util.ArrayList;

import java.util.List;

import java.util.Stack;

 

import javax.swing.tree.DefaultTreeSelectionModel;

import javax.swing.tree.TreeModel;

import javax.swing.tree.TreePath;

import javax.swing.tree.TreeSelectionModel;

 

public class CheckTreeSelectionModel extends DefaultTreeSelectionModel

{

       private static final long serialVersionUID = 1L;

       private TreeModel model;

 

       public CheckTreeSelectionModel(TreeModel model)

       {

              this.model = model;

              setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);

       }

 

       // tests whether there is any unselected node in the subtree of given path

       public boolean isPartiallySelected(TreePath path)

       {

              if (isPathSelected(path, true))

                     return false;

              TreePath[] selectionPaths = getSelectionPaths();

              if (selectionPaths == null)

                     return false;

              for (int j = 0; j < selectionPaths.length; j++)

              {

                     if (isDescendant(selectionPaths[j], path))

                            return true;

              }

              return false;

       }

 

       // tells whether given path is selected.

       // if dig is true, then a path is assumed to be selected, if

       // one of its ancestor is selected.

       public boolean isPathSelected(TreePath path, boolean dig)

       {

              if (!dig)

                     return super.isPathSelected(path);

              while (path != null && !super.isPathSelected(path))

                     path = path.getParentPath();

              return path != null;

       }

 

       // is path1 descendant of path2

       private boolean isDescendant(TreePath path1, TreePath path2)

       {

              Object obj1[] = path1.getPath();

              Object obj2[] = path2.getPath();

              for (int i = 0; i < obj2.length; i++)

              {

                     if (obj1[i] != obj2[i])

                            return false;

              }

              return true;

       }

 

       public void setSelectionPaths(TreePath[] pPaths)

       {

              throw new UnsupportedOperationException("not implemented yet!!!");

       }

 

       public void addSelectionPaths(TreePath[] paths)

       {

              // unselect all descendants of paths[]

              for (int i = 0; i < paths.length; i++)

              {

                     TreePath path = paths[i];

                     TreePath[] selectionPaths = getSelectionPaths();

                     if (selectionPaths == null)

                            break;

                     List<TreePath> toBeRemoved = new ArrayList<TreePath>();

                     for (int j = 0; j < selectionPaths.length; j++)

                     {

                            if (isDescendant(selectionPaths[j], path))

                                   toBeRemoved.add(selectionPaths[j]);

                     }

                     super.removeSelectionPaths((TreePath[]) toBeRemoved

                                   .toArray(new TreePath[0]));

              }

 

              // if all siblings are selected then unselect them and select parent

              // recursively

              // otherwize just select that path.

              for (int i = 0; i < paths.length; i++)

              {

                     TreePath path = paths[i];

                     TreePath temp = null;

                     while (areSiblingsSelected(path))

                     {

                            temp = path;

                            if (path.getParentPath() == null)

                                   break;

                            path = path.getParentPath();

                     }

                     if (temp != null)

                     {

                            if (temp.getParentPath() != null)

                                   addSelectionPath(temp.getParentPath());

                            else

                            {

                                   if (!isSelectionEmpty())

                                          removeSelectionPaths(getSelectionPaths());

                                   super.addSelectionPaths(new TreePath[]

                                   { temp });

                            }

                     } else

                            super.addSelectionPaths(new TreePath[]

                            { path });

              }

       }

 

       // tells whether all siblings of given path are selected.

       private boolean areSiblingsSelected(TreePath path)

       {

              TreePath parent = path.getParentPath();

              if (parent == null)

                     return true;

              Object node = path.getLastPathComponent();

              Object parentNode = parent.getLastPathComponent();

 

              int childCount = model.getChildCount(parentNode);

              for (int i = 0; i < childCount; i++)

              {

                     Object childNode = model.getChild(parentNode, i);

                     if (childNode == node)

                            continue;

                     if (!isPathSelected(parent.pathByAddingChild(childNode)))

                            return false;

              }

              return true;

       }

 

       public void removeSelectionPaths(TreePath[] paths)

       {

              for (int i = 0; i < paths.length; i++)

              {

                     TreePath path = paths[i];

                     if (path.getPathCount() == 1)

                            super.removeSelectionPaths(new TreePath[]

                            { path });

                     else

                            toggleRemoveSelection(path);

              }

       }

 

       // if any ancestor node of given path is selected then unselect it

       // and selection all its descendants except given path and descendants.

       // otherwise just unselect the given path

       private void toggleRemoveSelection(TreePath path)

       {

              Stack<TreePath> stack = new Stack<TreePath>();

              TreePath parent = path.getParentPath();

              while (parent != null && !isPathSelected(parent))

              {

                     stack.push(parent);

                     parent = parent.getParentPath();

              }

              if (parent != null)

                     stack.push(parent);

              else

              {

                     super.removeSelectionPaths(new TreePath[]

                     { path });

                     return;

              }

 

              while (!stack.isEmpty())

              {

                     TreePath temp = (TreePath) stack.pop();

                     TreePath peekPath = stack.isEmpty() ? path : (TreePath) stack

                                   .peek();

                     Object node = temp.getLastPathComponent();

                     Object peekNode = peekPath.getLastPathComponent();

                     int childCount = model.getChildCount(node);

                     for (int i = 0; i < childCount; i++)

                     {

                            Object childNode = model.getChild(node, i);

                            if (childNode != peekNode)

                                   super.addSelectionPaths(new TreePath[]

                                   { temp.pathByAddingChild(childNode) });

                     }

              }

              super.removeSelectionPaths(new TreePath[]

              { parent });

       }

}

 

package tree.threetree;

 

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.ItemListener;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

import java.awt.event.MouseListener;

 

import javax.swing.AbstractAction;

import javax.swing.ActionMap;

import javax.swing.ButtonGroup;

import javax.swing.ButtonModel;

import javax.swing.Icon;

import javax.swing.JCheckBox;

import javax.swing.SwingUtilities;

import javax.swing.event.ChangeListener;

import javax.swing.plaf.ActionMapUIResource;

 

public class TristateCheckBox extends JCheckBox

{

       private static final long serialVersionUID = 1L;

 

       /** This is a type-safe enumerated type */

       public static class State

       {

              private State()

              {

              }

       }

 

       public static final State NOT_SELECTED = new State();

       public static final State SELECTED = new State();

       public static final State DONT_CARE = new State();

 

       private final TristateDecorator model;

 

       @SuppressWarnings("serial")

       public TristateCheckBox(String text, Icon icon, State initial)

       {

              super(text, icon);

              // Add a listener for when the mouse is pressed

              super.addMouseListener(new MouseAdapter()

              {

                     public void mousePressed(MouseEvent e)

                     {

                            grabFocus();

                            model.nextState();

                     }

              });

              // Reset the keyboard action map

              ActionMap map = new ActionMapUIResource();

              map.put("pressed", new AbstractAction()

              {

                     public void actionPerformed(ActionEvent e)

                     {

                            grabFocus();

                            model.nextState();

                     }

              });

              map.put("released", null);

              SwingUtilities.replaceUIActionMap(this, map);

              // set the model to the adapted model

              model = new TristateDecorator(getModel());

              setModel(model);

              setState(initial);

       }

 

       public TristateCheckBox(String text, State initial)

       {

              this(text, null, initial);

       }

 

       public TristateCheckBox(String text)

       {

              this(text, DONT_CARE);

       }

 

       public TristateCheckBox()

       {

              this(null);

       }

 

       /** No one may add mouse listeners, not even Swing! */

       public void addMouseListener(MouseListener l)

       {

       }

 

       /**

        * Set the new state to either SELECTED, NOT_SELECTED or DONT_CARE. If state ==

        * null, it is treated as DONT_CARE.

        */

       public void setState(State state)

       {

              model.setState(state);

       }

 

       /**

        * Return the current state, which is determined by the selection status of

        * the model.

        */

       public State getState()

       {

              return model.getState();

       }

 

       public void setSelected(boolean b)

       {

              if (b)

              {

                     setState(SELECTED);

              } else

              {

                     setState(NOT_SELECTED);

              }

       }

 

       /**

        * Exactly which Design Pattern is this? Is it an Adapter, a Proxy or a

        * Decorator? In this case, my vote lies with the Decorator, because we are

        * extending functionality and "decorating" the original model with a more

        * powerful model.

        */

       private class TristateDecorator implements ButtonModel

       {

              private final ButtonModel other;

 

              private TristateDecorator(ButtonModel other)

              {

                     this.other = other;

              }

 

              private void setState(State state)

              {

                     if (state == NOT_SELECTED)

                     {

                            other.setArmed(false);

                            setPressed(false);

                            setSelected(false);

                     } else if (state == SELECTED)

                     {

                            other.setArmed(false);

                            setPressed(false);

                            setSelected(true);

                     } else

                     { // either "null" or DONT_CARE

                            other.setArmed(true);

                            setPressed(true);

                            setSelected(true);

                     }

              }

 

              /**

               * The current state is embedded in the selection / armed state of the

               * model.

               *

               * We return the SELECTED state when the checkbox is selected but not

               * armed, DONT_CARE state when the checkbox is selected and armed (grey)

               * and NOT_SELECTED when the checkbox is deselected.

               */

              private State getState()

              {

                     if (isSelected() && !isArmed())

                     {

                            // normal black tick

                            return SELECTED;

                     } else if (isSelected() && isArmed())

                     {

                            // don't care grey tick

                            return DONT_CARE;

                     } else

                     {

                            // normal deselected

                            return NOT_SELECTED;

                     }

              }

 

              /** We rotate between NOT_SELECTED, SELECTED and DONT_CARE. */

              private void nextState()

              {

                     State current = getState();

                     if (current == NOT_SELECTED)

                     {

                            setState(SELECTED);

                     } else if (current == SELECTED)

                     {

                            setState(DONT_CARE);

                     } else if (current == DONT_CARE)

                     {

                            setState(NOT_SELECTED);

                     }

              }

 

              /** Filter: No one may change the armed status except us. */

              public void setArmed(boolean b)

              {

              }

 

              /**

               * We disable focusing on the component when it is not enabled.

               */

              public void setEnabled(boolean b)

              {

                     setFocusable(b);

                     other.setEnabled(b);

              }

 

              /**

               * All these methods simply delegate to the "other" model that is being

               * decorated.

               */

              public boolean isArmed()

              {

                     return other.isArmed();

              }

 

              public boolean isSelected()

              {

                     return other.isSelected();

              }

 

              public boolean isEnabled()

              {

                     return other.isEnabled();

              }

 

              public boolean isPressed()

              {

                     return other.isPressed();

              }

 

              public boolean isRollover()

              {

                     return other.isRollover();

              }

 

              public void setSelected(boolean b)

              {

                     other.setSelected(b);

              }

 

              public void setPressed(boolean b)

              {

                     other.setPressed(b);

              }

 

              public void setRollover(boolean b)

              {

                     other.setRollover(b);

              }

 

              public void setMnemonic(int key)

              {

                     other.setMnemonic(key);

              }

 

              public int getMnemonic()

              {

                     return other.getMnemonic();

              }

 

              public void setActionCommand(String s)

              {

                     other.setActionCommand(s);

              }

 

              public String getActionCommand()

              {

                     return other.getActionCommand();

              }

 

              public void setGroup(ButtonGroup group)

              {

                     other.setGroup(group);

              }

 

              public void addActionListener(ActionListener l)

              {

                     other.addActionListener(l);

              }

 

              public void removeActionListener(ActionListener l)

              {

                     other.removeActionListener(l);

              }

 

              public void addItemListener(ItemListener l)

              {

                     other.addItemListener(l);

              }

 

              public void removeItemListener(ItemListener l)

              {

                     other.removeItemListener(l);

              }

 

              public void addChangeListener(ChangeListener l)

              {

                     other.addChangeListener(l);

              }

 

              public void removeChangeListener(ChangeListener l)

              {

                     other.removeChangeListener(l);

              }

 

              public Object[] getSelectedObjects()

              {

                     return other.getSelectedObjects();

              }

       }

}

 

package tree.threetree;

 

import javax.swing.JFrame;

import javax.swing.JScrollPane;

import javax.swing.JTree;

import javax.swing.UIManager;

import javax.swing.UnsupportedLookAndFeelException;

import javax.swing.tree.DefaultMutableTreeNode;

import javax.swing.tree.DefaultTreeCellRenderer;

import javax.swing.tree.DefaultTreeModel;

import javax.swing.tree.TreeNode;

import javax.swing.tree.TreePath;

import javax.swing.tree.TreeSelectionModel;

 

public class TristateTreeDemo

{

       public static void main(String args[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException

       {

              UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

             

              DefaultMutableTreeNode world = new DefaultMutableTreeNode("World");

 

              DefaultMutableTreeNode country1 = new DefaultMutableTreeNode("country1");

              DefaultMutableTreeNode city1 = new DefaultMutableTreeNode("city1");

              DefaultMutableTreeNode city1_1 = new DefaultMutableTreeNode("city1");

              country1.add(city1);

              country1.add(city1_1);

              world.add(country1);

 

              DefaultMutableTreeNode country2 = new DefaultMutableTreeNode("country2");

              DefaultMutableTreeNode city2 = new DefaultMutableTreeNode("city2");

              country2.add(city2);

              world.add(country2);

 

              DefaultMutableTreeNode country3 = new DefaultMutableTreeNode("country3");

              DefaultMutableTreeNode city3 = new DefaultMutableTreeNode("city3");

              country3.add(city3);

              world.add(country3);

 

              DefaultMutableTreeNode country4 = new DefaultMutableTreeNode("country4");

              DefaultMutableTreeNode city4 = new DefaultMutableTreeNode("city4");

              country4.add(city4);

              world.add(country4);

 

              TreeNode root = world;

              DefaultTreeModel model = new DefaultTreeModel(root);

              JTree tree = new JTree(model);

              DefaultTreeCellRenderer myRenderer = new DefaultTreeCellRenderer();

              tree.setCellRenderer(myRenderer);

              CheckTreeManager checkTreeManager = new CheckTreeManager(tree);

             

              //下面设置默认路径选中

              TreeNode[] nodes = model.getPathToRoot(city1);

              TreePath hh1 = new TreePath(nodes);

              nodes = model.getPathToRoot(city2);

              TreePath hh2 = new TreePath(nodes);

              nodes = model.getPathToRoot(city3);

              TreePath hh3 = new TreePath(nodes);        

              TreeSelectionModel selModel = checkTreeManager.getSelectionModel();

              selModel.addSelectionPaths(new TreePath[]

              { hh1, hh2, hh3 });

             

              //展开所有节点

              for (int i = 0; i < tree.getRowCount(); i++)

              {

                     tree.expandRow(i);

              }

              JScrollPane TreePanel = new JScrollPane(tree);

              JFrame frame = new JFrame("Demo");

              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

              frame.add(TreePanel);

              frame.setBounds(200, 200, 200, 200);

              frame.setVisible(true);

 

       }

}

 

 

三态选择树实例二

package tree.threetree;

 

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.ItemListener;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

import java.awt.event.MouseListener;

 

import javax.swing.AbstractAction;

import javax.swing.ActionMap;

import javax.swing.ButtonGroup;

import javax.swing.ButtonModel;

import javax.swing.Icon;

import javax.swing.JCheckBox;

import javax.swing.SwingUtilities;

import javax.swing.event.ChangeListener;

import javax.swing.plaf.ActionMapUIResource;

 

public class TristateCheckBox extends JCheckBox

{

       private static final long serialVersionUID = 1L;

 

       /** This is a type-safe enumerated type */

       public static class State

       {

              private State()

              {

              }

       }

 

       public static final State NOT_SELECTED = new State();

       public static final State SELECTED = new State();

       public static final State DONT_CARE = new State();

 

       private final TristateDecorator model;

 

       @SuppressWarnings("serial")

       public TristateCheckBox(String text, Icon icon, State initial)

       {

              super(text, icon);

              // Add a listener for when the mouse is pressed

              super.addMouseListener(new MouseAdapter()

              {

                     public void mousePressed(MouseEvent e)

                     {

                            grabFocus();

                            model.nextState();

                     }

              });

              // Reset the keyboard action map

              ActionMap map = new ActionMapUIResource();

              map.put("pressed", new AbstractAction()

              {

                     public void actionPerformed(ActionEvent e)

                     {

                            grabFocus();

                            model.nextState();

                     }

              });

              map.put("released", null);

              SwingUtilities.replaceUIActionMap(this, map);

              // set the model to the adapted model

              model = new TristateDecorator(getModel());

              setModel(model);

              setState(initial);

       }

 

       public TristateCheckBox(String text, State initial)

       {

              this(text, null, initial);

       }

 

       public TristateCheckBox(String text)

       {

              this(text, DONT_CARE);

       }

 

       public TristateCheckBox()

       {

              this(null);

       }

 

       /** No one may add mouse listeners, not even Swing! */

       public void addMouseListener(MouseListener l)

       {

       }

 

       /**

        * Set the new state to either SELECTED, NOT_SELECTED or DONT_CARE. If state ==

        * null, it is treated as DONT_CARE.

        */

       public void setState(State state)

       {

              model.setState(state);

       }

 

       /**

        * Return the current state, which is determined by the selection status of

        * the model.

        */

       public State getState()

       {

              return model.getState();

       }

 

       public void setSelected(boolean b)

       {

              if (b)

              {

                     setState(SELECTED);

              } else

              {

                     setState(NOT_SELECTED);

              }

       }

 

       /**

        * Exactly which Design Pattern is this? Is it an Adapter, a Proxy or a

        * Decorator? In this case, my vote lies with the Decorator, because we are

        * extending functionality and "decorating" the original model with a more

        * powerful model.

        */

       private class TristateDecorator implements ButtonModel

       {

              private final ButtonModel other;

 

              private TristateDecorator(ButtonModel other)

              {

                     this.other = other;

              }

 

              private void setState(State state)

              {

                     if (state == NOT_SELECTED)

                     {

                            other.setArmed(false);

                            setPressed(false);

                            setSelected(false);

                     } else if (state == SELECTED)

                     {

                            other.setArmed(false);

                            setPressed(false);

                            setSelected(true);

                     } else

                     { // either "null" or DONT_CARE

                            other.setArmed(true);

                            setPressed(true);

                            setSelected(true);

                     }

              }

 

              /**

               * The current state is embedded in the selection / armed state of the

               * model.

               *

               * We return the SELECTED state when the checkbox is selected but not

               * armed, DONT_CARE state when the checkbox is selected and armed (grey)

               * and NOT_SELECTED when the checkbox is deselected.

               */

              private State getState()

              {

                     if (isSelected() && !isArmed())

                     {

                            // normal black tick

                            return SELECTED;

                     } else if (isSelected() && isArmed())

                     {

                            // don't care grey tick

                            return DONT_CARE;

                     } else

                     {

                            // normal deselected

                            return NOT_SELECTED;

                     }

              }

 

              /** We rotate between NOT_SELECTED, SELECTED and DONT_CARE. */

              private void nextState()

              {

                     State current = getState();

                     if (current == NOT_SELECTED)

                     {

                            setState(SELECTED);

                     } else if (current == SELECTED)

                     {

                            setState(DONT_CARE);

                     } else if (current == DONT_CARE)

                     {

                            setState(NOT_SELECTED);

                     }

              }

 

              /** Filter: No one may change the armed status except us. */

              public void setArmed(boolean b)

              {

              }

 

              /**

               * We disable focusing on the component when it is not enabled.

               */

              public void setEnabled(boolean b)

              {

                     setFocusable(b);

                     other.setEnabled(b);

              }

 

              /**

               * All these methods simply delegate to the "other" model that is being

               * decorated.

               */

              public boolean isArmed()

              {

                     return other.isArmed();

              }

 

              public boolean isSelected()

              {

                     return other.isSelected();

              }

 

              public boolean isEnabled()

              {

                     return other.isEnabled();

              }

 

              public boolean isPressed()

              {

                     return other.isPressed();

              }

 

              public boolean isRollover()

              {

                     return other.isRollover();

              }

 

              public void setSelected(boolean b)

              {

                     other.setSelected(b);

              }

 

              public void setPressed(boolean b)

              {

                     other.setPressed(b);

              }

 

              public void setRollover(boolean b)

              {

                     other.setRollover(b);

              }

 

              public void setMnemonic(int key)

              {

                     other.setMnemonic(key);

              }

 

              public int getMnemonic()

              {

                     return other.getMnemonic();

              }

 

              public void setActionCommand(String s)

              {

                     other.setActionCommand(s);

              }

 

              public String getActionCommand()

              {

                     return other.getActionCommand();

              }

 

              public void setGroup(ButtonGroup group)

              {

                     other.setGroup(group);

              }

 

              public void addActionListener(ActionListener l)

              {

                     other.addActionListener(l);

              }

 

              public void removeActionListener(ActionListener l)

              {

                     other.removeActionListener(l);

              }

 

              public void addItemListener(ItemListener l)

              {

                     other.addItemListener(l);

              }

 

              public void removeItemListener(ItemListener l)

              {

                     other.removeItemListener(l);

              }

 

              public void addChangeListener(ChangeListener l)

              {

                     other.addChangeListener(l);

              }

 

              public void removeChangeListener(ChangeListener l)

              {

                     other.removeChangeListener(l);

              }

 

              public Object[] getSelectedObjects()

              {

                     return other.getSelectedObjects();

              }

       }

}

 

package tree.threetree1;

 

import java.awt.Component;

import java.util.ArrayList;

import java.util.Enumeration;

import java.util.HashMap;

import java.util.Iterator;

 

import javax.swing.JTree;

import javax.swing.event.TreeSelectionEvent;

import javax.swing.event.TreeSelectionListener;

import javax.swing.tree.DefaultMutableTreeNode;

import javax.swing.tree.DefaultTreeCellRenderer;

import javax.swing.tree.TreeNode;

import javax.swing.tree.TreePath;

 

import tree.threetree.TristateCheckBox;

 

public class ThreeCheckboxTree

{

       // 用一个HashMap来保存每个节点的选择状态

       private HashMap<TreeNode, TristateCheckBox.State> hm = new HashMap<TreeNode, TristateCheckBox.State>();

 

       public ThreeCheckboxTree(JTree jTree)

       {

              DefaultMutableTreeNode root = (DefaultMutableTreeNode) jTree.getModel().getRoot();

              for (Enumeration<?> em = root.depthFirstEnumeration(); em.hasMoreElements();)

              {

                     hm.put((DefaultMutableTreeNode) em.nextElement(), TristateCheckBox.NOT_SELECTED);

              }

              jTree.setCellRenderer(new MyTreeWithCheckboxRenderer());

              jTree.addTreeSelectionListener(new MyTreeWithCheckboxSelectionListener());

       }

 

       /** 返回所有选中的路径 */

       public TreePath[] getSelectionPaths()

       {

              Iterator<?> it = hm.keySet().iterator();

              ArrayList<TreePath> al = new ArrayList<TreePath>();

              while (it.hasNext())

              {

                     DefaultMutableTreeNode o = (DefaultMutableTreeNode) it.next();

                     if (o.isLeaf() && ((TristateCheckBox.State) hm.get(o)).equals(TristateCheckBox.SELECTED))

                     {

                            al.add(new TreePath(o.getPath()));

                     }

              }

              return (TreePath[]) al.toArray(new TreePath[0]);

       }

 

       class MyTreeWithCheckboxSelectionListener implements TreeSelectionListener

       {

              public void valueChanged(TreeSelectionEvent e)

              {

                     JTree jTree = (JTree) (e.getSource());

                     DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree.getLastSelectedPathComponent();

                     if (node == null)

                     {

                            return;

                     }

                     //修改当前节点的状态

                     if (((TristateCheckBox.State) hm.get(node)).equals(TristateCheckBox.SELECTED))

                     {

                            hm.put(node, TristateCheckBox.NOT_SELECTED);

                     } else

                     {

                            hm.put(node, TristateCheckBox.SELECTED);

                     }

                     updateAllParentNodes(node);

                     updateAllChildNodes(node);

                     jTree.setSelectionPath(null);

                     jTree.repaint();

              }

 

              /** 用递归方法修改从当前节点到根节点的所有节点的状态 */

              public void updateAllParentNodes(DefaultMutableTreeNode node)

              {

                     TristateCheckBox.State status = (TristateCheckBox.State) hm.get(node);

                     if (node.isRoot())

                     {

                            return;

                     }

                     hm.put(node.getParent(), status);

                     for (Enumeration<?> em = node.getParent().children(); em.hasMoreElements();)

                     {

                            DefaultMutableTreeNode tn = (DefaultMutableTreeNode) em.nextElement();

                            if (!((TristateCheckBox.State) hm.get(tn)).equals(status))

                            {

                                   hm.put(node.getParent(), TristateCheckBox.DONT_CARE);

                                   break;

                            }

                     }

                     updateAllParentNodes((DefaultMutableTreeNode) node.getParent());

              }

 

              /** 用递归方法修改以当前节点为根的子树的所有节点的状态 */

              public void updateAllChildNodes(DefaultMutableTreeNode node)

              {

                     TristateCheckBox.State status = (TristateCheckBox.State) hm.get(node);

                     for (Enumeration<?> em = node.depthFirstEnumeration(); em.hasMoreElements();)

                     {

                            DefaultMutableTreeNode tn = (DefaultMutableTreeNode) em.nextElement();

                            hm.put(tn, status);

                     }

              }

       }

 

       class MyTreeWithCheckboxRenderer extends DefaultTreeCellRenderer

       {

              private static final long serialVersionUID = 1L;

 

              public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,

                            boolean leaf, int row, boolean hasFocus)

              {

                     TristateCheckBox checkBox = new TristateCheckBox(value.toString());

                     checkBox.setOpaque(false);

                     DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;

                     checkBox.setState(((TristateCheckBox.State) hm.get(node)));

                     return checkBox;

              }

       }

}

 

package tree.threetree1;

 

import java.awt.BorderLayout;

import java.awt.Dimension;

 

import javax.swing.JFrame;

import javax.swing.JPanel;

import javax.swing.JScrollPane;

import javax.swing.JTree;

import javax.swing.UIManager;

import javax.swing.UnsupportedLookAndFeelException;

 

public class ThreeCheckboxTreeDemo extends JPanel

{

       private static final long serialVersionUID = 1L;

 

       public ThreeCheckboxTreeDemo()

       {

              setLayout(new BorderLayout());

              JTree tree = new JTree();

              new ThreeCheckboxTree(tree);

              JScrollPane jsp = new JScrollPane(tree);

              jsp.setPreferredSize(new Dimension(500, 400));

              add(jsp);        

       }

 

       public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException

       {

              UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

              ThreeCheckboxTreeDemo panel = new ThreeCheckboxTreeDemo();

              JFrame frame = new JFrame("ThreeCheckboxTreeDemo");

              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

              panel.setOpaque(true);

              frame.setContentPane(panel);

              frame.pack();

              frame.setVisible(true);

             

       }

}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目录 目录 1 (一) Spring 开发 Swing GUI 简介——依赖注入和富客户机 5 关于本教程 5 前提条件 6 Spring 和依赖注入概述 7 什么是 Spring 框架? 7 什么是依赖注入? 7 环境设置 7 选择编译环境 7 设置 Ant 8 通过 Ant 自动下载依赖软件 10 设置 Maven 10 通过 Maven 自动下载依赖软件 12 设置 Eclipse 13 下载依赖的 JAR 文件并在 Eclipse 的 classpath 中定义这种依赖性 15 创建 to-do 列表:基本的 Swing 和 Spring 应用程序设置 17 创建 MainFrame、Launcher 和 ToDo 类 17 创建 Spring app-context.xml bean 定义文件 19 运行应用程序 20 定义 bean 属性 21 创建 to-do 列表:创建一个可重用组件并在表中显示数据 23 创建一个可重用的面板 23 将 bean 组合在一起 24 添加一个表并重用这个面板 26 定义表模型 28 显示列表中的项 29 创建 to-do 列表:完成 —— 按钮和监听程序 31 创建按钮和监听程序 32 组合按钮和监听程序 35 Spring Rich Client Project 37 Spring Rich Client Project 概述 37 结束语 38 (二) 适用于各类Swing应用的通用数据验证模块 39 项目创建好后,加入类库: 41 然后写一个persistence bean: 41 Java代码 41 我称这个类为HibernateValidationUI,代码如下: 43 Java代码 43 类中用到的Java2DIconFactory代码如下: 47 Java代码 47 Factory类 49 Java代码 49 最后,我们可以编写一个Demo application来看看效果如何,代码如下: 51 Java代码 51 总结: 55 (三) 对JTree从创建到使用详解 56 (四) JTree的使用方法 57 JTreeDemo.java源程序 57 经验汇总 60 1. 初始化 60 2. 三个经常使用的取值函数 60 3. 根据node得到path: 60 4. 根据Path展开到该节点 60 5. 根据path设定该节点选定 61 6. 选中节点的方法 61 7. 滚动到可见位置 61 8. 给JTree添加右键弹出菜单 61 9. 关于JTree的展开 61 10. 如何遍历JTree 62 (五) JTree右键菜单实现编辑、添加、删除节点 63 Test.java源代码 63 (六) 功能齐全的JTree例子 66 TreeEditTest.java源代码 66 (七) JTree控件的使用 70 构造函数: 70 TreeModel接口 70 DefaultTreeModel缺省版本 71 TreeNode接口 71 TreeExpansionListener接口 71 TreeCellRenderer 72 例子: 73 (八) 如何为JTree添加右键菜单? 75 (九) 如何使JTextArea随着窗体的变化自动调整大小 76 TextAreaTest源代码 76 (十) JAVA swing编程JTree实现系统目录 77 FileTree1.java源代码 77 (十一) Java Swing中的JTree模型 85 Swing.tree包中的主要类名称实现 85 1. 构建树模型 86 2. 树结点 86 树结构详细类图 86 2.1 TreeNode接口 86 2.2 MutableTreeNode接口 87 2.3 DefaultMutableTreeNode类 88 3. 编辑树 88 3.1获得结点路径 88 3.2编辑结点 88 3.3视图显示 89 4. 查找树 89 5. 绘制结点 90 (十二) JTree鼠标左键的双击事件选用那个监听器 91 MouseDemo.java源代码 92 (十三) JTree 92 JTree的构造函数: 93 JTreeDefaultDemo.java源代码 93 (十四) JTree 应用 96 Frame1.java源代码 96 MyDefaultTreeCellRenderer.java源代码 98 (十五) JTree控件 100 树和节点的基本概念 100 有关树JTree的类和接口 100 代码实例:构建一棵树 101 相关语句解释 101 (十六) JTree应用示例——文件路径 103 AnimatedIconTreeExample.java源代码 103 //内部类NodeImageObserver.java源代码 105 //IconNodeRenderer.java源代码 106 //IconNode.java源代码 107 (十七) Swing 学习笔记 108 Swing API 包括18个公共包: 108 例程1.1 HelloWorldSwing.java 109 例程2.2 HelloWorldJFrame.java 110 (十八) 动态加载文件树的java程序 111 FileSystemTree.java源代码 112 //内部类 TreeWillExpandListenerImp.java 114 (十九) 向 Java 应用程序伸出援助之手——用 JavaHelp 2.0 构建下一个 Java 应用程序的帮助系统 115 入门 116 使用 HelpSet 117 HelpSet 数据文件 118 helpset 文件 118 maps 部分 119 view 部分 119 presentation 部分 120 implementation 部分 121 map 文件 121 导航文件 121 TOC 122 Index 122 Glossary 123 Favorites 123 主题文件 123 在 Java 应用程序中调用 JavaHelp 124 自定义外观 125 配置图标 125 基于文字的标签还是基于图像的标签? 125 要工具栏还是不要工具栏? 125 设置字体 126 使用展示窗口 127 <object> 标签 128 四种 activator 129 添加内容敏感的帮助 130 窗口级帮助 131 字段级帮助 131 屏幕级帮助 133 添加嵌入帮助 135 添加搜索功能 136 停用词 137 自定义停用词列表 137 合并 helpset 138 静态和动态合并 139 添加轻量级组件 141 基于服务器的帮助 144 设置 144 JavaHelp 服务器 bean 144 JavaScript 文件 145 JSP 文件 145 测试服务器端帮助 148 结束语 149
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值