Java---Swing(3)---------------------JTree

    技术2022-05-11  59

    使用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对象,并决定此节点是否允

                           许具有子节点。

     

    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中找到此类所提供

    的方法。

     

    10-7:JTree的事件处理模式:

        在此节中,我们将详细介绍JTree两个常用的事件与处理,分别是TreeModeEventTreeSelectionEvent.

    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 nodleaf node)的节点。

    TreePath             getTreePath():取得目前位置的Tree Path.

    String               toString():取得蝗字符串表示法.

     

        TreeModelEventgetTreePath()方法就可以得到TreePath对象,此对象就能够让我们知道用户目前正选哪一个节点,

    TreePath类最常用的方法为:

         public  Object getLastPathComponent():取得最深(内)层的节点。

         public int    getPathCount():取得此path上共有几个节点.

        我们来看下面这个例子,用户可以在Tree上编辑节点,按下[Enter]键后就可以改变原有的值,并将改变的值显示在下面的

    JLabel:

     

        /*本方法实作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) {}

            //DefaultMutableTreeNodegetUserObject()方法取得节点的内容,或是写成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();

            //JTreegetRowForLocation()方法会返回节点的列索引值。例如本例中,“本机磁盘(D:)”的列索引值为4,此索引值

            //会随着其他数据夹的打开或收起而变支,但“资源管理器”的列索引值恒为0.

                  int rowLocation = tree.getRowForLocation(e.getX(), e.getY());

     

                 /*JTreegetPathForRow()方法会取得从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的例子,下面这个例子我们可以让用户自行增加、删除与修改节点:

    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种选择模式。

       下面这个范例,当用户点选了一个文件名时,就会将文件的内容显示出来。

    10-8:JTree的其他操作:

         我们在之前小节中曾说到Tree中的每一个节点都是一个TreeNode,并可利用JTreesetEditable()方法设置节点是否可编辑,

    若要在Tree中找寻节点的父节点或子节点,或判断是否为树节点,皆可由实作TreeNode界面做到,但要编辑节点呢?java将编辑

    节点的任务交给TreeCellEditor,TreeCellEditor本身是一个界面,里面只定义了getTreeCellEditor Component()方法,你可以实

    作此方法使节点具有编辑的效果。不过你不用这么辛苦去实作这个方法,java本身提供了DefaultTreeCellEditor类来实作此方法

    ,亦提供了其他许多方法,例如取得节点内容(getCellEditorValue())         、设置节点字体(setFont())、决定节点是否可编辑

    (isCellEditable())等等。除非你觉得DefaultTreeCellEditor所提供的功能不够,你才需要去实作TreeCellEditor界面。你可以利

    JTreegetCellEditor()方法取得DefaultTreeCellEditor对象。当我们编辑节点时会触发ChangeEvent事件,你可以实作

    CellEditorListener界面来处理此事件,CellEditorListener界面包括两个方法,分别是editingStopped(ChangeEvent e)

    editingCanceled(ChangeEvent e).若你没有实作TreeCellEditor界面,系统会以默认的DefaultTreeCellEdtior类来处理掉这两个

    方法(你可以在DefaultTreeCellEditor中找到这两个方法),因此你无须再编写任何的程序。

         另外,JTree还有一种事件处理模式,那就是TreeExpansionEvent事件。要处理这个事件你必须实作TreeExpansionListener

    界面,此界面定义了两个方法,分别是treeCollapsed(TreeExpansionEvent e)treeExpanded(TreeExpansionEvent e).当节点展

    开时系统就会自动调用treeExpanded()方法,当节点合起来时,系统就会自动调用treeCollapsed()方法。

     

    最新回复(0)