在此节中,我们将详细介绍JTree两个常用的事件与处理,分别是TreeModeEvent与TreeSelectionEvent. 10-7-1:处理TreeModeEvent事件:
当树的结构上有任何改变时,例如节点值改变了、新增节点、删除节点等,都会TreeModelEvent事件,要处理这样的事件必须实 作TreeModelListener界面,此界面定义了4个方法,如下所示:
TreeModelEvent类本身提供了5个方法,帮我们取得事件的信息,如下所示:
由TreeModelEvent的getTreePath()方法就可以得到TreePath对象,此对象就能够让我们知道用户目前正选哪一个节点, TreePath类最常用的方法为:
我们来看下面这个例子,用户可以在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) {
}
}
}
}