JTree是Swing里的一种树形结构,感觉有些场合能起到意想不到的作用。

树结点新选中的事件

说是”新选中”而不是”选中”或”单击”,因为监听器实际上是在看选中者的某个值有没有改变,连续的选中不会触发这件事,单击也仅仅是”选中”的一条不必要的途径,这些都不会产生TreeSelectionEvent对象。

简述

选中事件的监听比较方便,不能对每个结点注册监听器,只能对整棵树注册一个实现了TreeSelectionListener接口的监听器,然后实现其valueChanged()方法,在方法中用JTree对象的getLastSelectedPathComponent()方法可以获取当前选择的第一个结点中的最后一个路径组件。

一般要考虑的仅仅是叶子结点,所以可以把这个组件强制转换成叶子结点的数据类型,如DefaultMutableTreeNode标准树结点,然后使用isLeaf()方法可以判定它是不是叶子结点。

在经过这样的筛选后,已经确定它是叶子结点了,还需要知道这个结点到底是哪个结点。如果结点之间的名称各不相同的话,可以使用其toString()方法去判断这个结点对应的字符串,这有些特别,因为之前学过的组件明明是使用事件对象的getActionCommand()方法然后用equals()作字符串的比较的。

打开DefaultMutableTreeNode源码看一下,其构造器中传入的实际上是一个Object对象:

/**
     * Creates a tree node with no parent, no children, but which allows
     * children, and initializes it with the specified user object.
     *
     * @param userObject an Object provided by the user that constitutes
     *                   the node's data
     */
    public DefaultMutableTreeNode(Object userObject) {
        this(userObject, true);
    }

然后看一下它的toString()方法,实际就是在做这个构造时传入的Object对象的toString(),当然对象不存在时候要返回一个空串:

/**
     * Returns the result of sending <code>toString()</code> to this node's
     * user object, or the empty string if the node has no user object.
     *
     * @see     #getUserObject
     */
    public String toString() {
        if (userObject == null) {
            return "";
        } else {
            return userObject.toString();
        }
    }
程序
import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

//实现TreeSelectionListener接口以成为树的选中事件的监听器
class TestJTree extends JFrame implements TreeSelectionListener {
    JTree jt;// 为了对valueChanged()方法可见,在这里声明

    TestJTree() {
        super("JTree的使用");
        // DefaultMutableTreeNode是树结构中通用的结点
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root Node");
        DefaultMutableTreeNode nodeA = new DefaultMutableTreeNode("A Node");
        // 用结点之间add的方法来实现嵌套(建立树结点的父子关系)
        root.add(nodeA);
        root.add(new DefaultMutableTreeNode("B Node"));// 可以用匿名对象
        DefaultMutableTreeNode nodeC = new DefaultMutableTreeNode("C Node");// 也可以创建了再add
        nodeA.add(nodeC);
        nodeA.add(new DefaultMutableTreeNode("D Node"));
        // 用实现了TreeModel接口的DefaultTreeModel类来指定树的根结点
        DefaultTreeModel dtm = new DefaultTreeModel(root);
        // 用这个根结点就可以去建立JTree树了
        jt = new JTree(dtm);
        jt.addTreeSelectionListener(this);// 为这棵树注册监听器

        this.setBounds(700, 150, 250, 400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.add(jt);
        this.setVisible(true);
    }

    @Override
    public void valueChanged(TreeSelectionEvent e) {
        if (e.getSource() == jt) // 如果是要相应的那棵树
        {
            // 获取当前选择的第一个结点中的最后一个路径组件
            DefaultMutableTreeNode dmt = (DefaultMutableTreeNode) jt.getLastSelectedPathComponent();
            // 如果是叶子结点
            if (dmt.isLeaf()) {
                String str = dmt.toString();// 叶子结点的字符串
                // 判断
                if (str.equals("B Node")) {
                    System.out.println("B Node");
                } else if (str.equals("C Node")) {
                    System.out.println("C Node");
                } else if (str.equals("D Node")) {
                    System.out.println("D Node");
                }
            }
        }

    }
}

public class Main {

    public static void main(String[] args) {
        TestJTree tj = new TestJTree();
    }

}
运行结果

(新选中叶结点时会打印相应的字符串)

Treeselect怎么监听获取焦点 treeselectionlistener_Swing


C Node

D Node

B Node

D Node

树结点双击的事件

因为不能为树中的结点注册监听器,双击的事件也是为JTree对象注册的监听器。

简述

查了好久,发现JTree对象有一个非常实用的的方法getPathForLocation()能够根据指定的坐标点来获取点击的那个结点在树中的逻辑路径TreePath对象。有了这个方法就不需要去手工判断点击的位置处是哪个对象了。

获得了TreePath路径对象后,就可以使用它的getLastPathComponent()获取这棵树上这条路径上的最后一个组件了,还是强制转换成结点类型然后做操作就可以了。

实际使用时,双击事件也往往只需要去捕获叶子结点的,只要和前面一样做一个isLeaf()判断就可以了,我这里没写。

需要注意的是,对某些空白处双击时,还是属于在树上触发了双击事件,然而getPathForLocation()肯定获取不到路径了,返回的是一个null,在后面对这个对象的操作都必须包含在判断非null中才行,否则对null取成员方法显然是错误的。

程序
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

class TestJTree extends JFrame {

    TestJTree() {
        super("JTree的使用");
        // DefaultMutableTreeNode是树结构中通用的结点
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root Node");
        DefaultMutableTreeNode nodeA = new DefaultMutableTreeNode("A Node");
        // 用结点之间add的方法来实现嵌套(建立树结点的父子关系)
        root.add(nodeA);
        root.add(new DefaultMutableTreeNode("B Node"));// 可以用匿名对象
        DefaultMutableTreeNode nodeC = new DefaultMutableTreeNode("C Node");// 也可以创建了再add
        nodeA.add(nodeC);
        nodeA.add(new DefaultMutableTreeNode("D Node"));
        // 用实现了TreeModel接口的DefaultTreeModel类来指定树的根结点
        DefaultTreeModel dtm = new DefaultTreeModel(root);
        // 用这个根结点就可以去建立JTree树了
        JTree jt = new JTree(dtm);
        // 为这棵树注册监听器,用匿名的适配器覆写鼠标点击方法
        jt.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                // 如果在这棵树上点击了2次,即双击
                if (e.getSource() == jt && e.getClickCount() == 2) {
                    // 按照鼠标点击的坐标点获取路径
                    TreePath selPath = jt.getPathForLocation(e.getX(), e.getY());
                    if (selPath != null)// 谨防空指针异常!双击空白处是会这样
                    {
                        System.out.println(selPath);// 输出路径看一下
                        // 获取这个路径上的最后一个组件,也就是双击的地方
                        DefaultMutableTreeNode node = (DefaultMutableTreeNode) selPath.getLastPathComponent();
                        System.out.println(node.toString());// 输出这个组件toString()的字符串看一下
                    }
                }

            }
        });

        this.setBounds(700, 150, 250, 400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.add(jt);
        this.setVisible(true);
    }

}

public class Main {

    public static void main(String[] args) {
        TestJTree tj = new TestJTree();
    }

}
运行结果

Treeselect怎么监听获取焦点 treeselectionlistener_JavaSE_02


[Root Node, A Node, C Node]

C Node

[Root Node]

Root Node

[Root Node]

Root Node

[Root Node, B Node]

B Node

[Root Node, A Node]

A Node

[Root Node, A Node, D Node]

D Node