Java Swing组件:树

       树是一种使用非常广泛的数据结构,计算机中的目录和文件就是以树结构形式来管理的。在Swing中,使用JTree来创建树结构,其主要构造方法如下:

  • JTree():使用默认数据模型创建一棵树。
  • JTree(Object[] value):使用指定数组中的每个元素元素作为子节点,创建一棵不显示根节点的树。
  • JTree(TreeModel newModel):使用指定的数据模型创建一棵显示根节点的树。
  • JTree(TreeNode root):创建一棵带有指定根节点的树。

       与表格类似,树的设计也采用了MVC模式,其中,JTree对象并没有包含实际的数据,它只是提供了数据的一个视图,对应的数据存储在树的数据模型中。在Swing中,树的数据模型采用TreeModel接口实现类的对象来管理。在实际应用中,一般使用DefaultTreeModel对象来管理树的数据模型。DefaultTreeModel类是TreeModel接口的一个实现类,它提供了TreeModel接口的默认实现。

       DefaultTreeModel类的构造方法如下:

  • DefaultTreeModel(TreeNode root):创建一个指定根节点的数据模型。
  • DefaultTreeModel(TreeNode root, boolean asksAllowsChildren):创建一个指定根节点的数据模型,如果asksAllowsChildren的取值为true,则节点的isLeaf()方法将被忽略,所有节点都被认为可以有子节点,如果其取值为false,则节点的isLeaf()方法将决定节点是否也可以有子节点。

       树中的每一行包含一个数据项,称为树的节点(node),每棵树只有一个根节点(root node),其它所有节点都是根节点的子孙节点。一个节点可以拥有子节点也可以不拥有子节点,我们称那些可有拥有子节点(不管当前是否有子节点)的节点称为分支节点(branch node),而不能拥有子节点的节点称为叶子节点(leaf node)。在Swing中,树的节点采用TreeNode接口实现类的对象来管理。在实际应用中,一般使用DefaultMutableTreeNode类的对象来创建树的节点,该类是TreeNode接口的子接口MutableTreeNode的实现类。

       DefaultMutableTreeNode类的构造方法如下:

  • DefaultMutableTreeNode():创建一个没有父节点和子节点,但允许有子节点的树节点。
  • DefaultMutableTreeNode(Object userObject):创建一个没有父节点和子节点,但允许有子节点的树节点,并使用指定的用户对象对其进行初始化。
  • DefaultMutableTreeNode(Object userObject,boolean allowsChildren): 创建一个没有父节点和子节点的树节点,使用指定的用户对象对其进行初始化,可以设置是否允许有子节点。

下面的代码演示了树的创建一般过程,其所创建的树结构如图1所示。

//创建树的根节点
DefaultMutableTreeNode root=new DefaultMutableTreeNode("专业");
//创建树的节点
DefaultMutableTreeNode node1=new DefaultMutableTreeNode("理学");
DefaultMutableTreeNode node2=new DefaultMutableTreeNode("工学");
DefaultMutableTreeNode node3=new DefaultMutableTreeNode("管理学");
DefaultMutableTreeNode node21=new DefaultMutableTreeNode("电子信息类");
DefaultMutableTreeNode node22=new DefaultMutableTreeNode("计算机类");
//将node21和node22作为子节点添加到node2中
node2.add(node21);node2.add(node22);
//将node1、node2和node3作为子节点添加到根节点中
root.add(node1);root.add(node2);root.add(node3);
//创建树的数据模型
DefaultTreeModel treeModel=new DefaultTreeModel(root);
//创建树
JTree tree=new JTree(treeModel);

图1. 树结构

       DefaultMutableTreeNode是构造树结构的核心类,其提供的常用方法如下:

  • void add(MutableTreeNode newchild):从newchild的父节点(如果它具有父节点)中将其删除,并添加到此节点的子节点数组的末尾。
  • void insert(MutableTreeNode newChild,int childIndex):从newChild的父节点中将其删除,并加入到此节点的子节点数组中的指定位置。
  • void remove(MutableTreeNode aChild):从此节点的子节点数组中删除aChild,并将其父节点设置为null。
  • void remove(int childIndex):从节点的子节点数组中移除指定索引处的子节点,并将其父节点设置为null。
  • int getChildCount():返回此节点的子节点数目。
  • TreeNode getChildAt(int index):返回此节点的子节点数组中指定索引处的子节点。
  • int getIndex(TreeNode aChild):返回此节点的子节点数组中指定子节点的索引。
  • int getDepth():返回以此节点为根的深度,即从此节点到叶子的最长距离。
  • boolean isLeaf():如果此节点没有子节点,则返回true,否则,返回false。
  • void setAllowsChildren():设置此节点是否允许拥有子节点。
  • boolean isRoot():如果此节点是树的根节点,则返回true,否则,返回false。
  • TreeNode getParent():返回此节点的父节点,如果没有父节点则返回null。
  • Int getLevel():返回此节点的层级数,即从根节点到此节点的距离。
  • TreeNode[] getPath():返回从根节点到此节点的路径。
  • void setUserObject(Object userObject):设置此节点的用户对象。
  • Object getUserObject():获取此节点的用户对象。
  • Object[] getUserObjectPath():获取从根节点到此节点的用户对象序列。

       JTree类提供了注册树选择事件监听器方法,语法格式如下:

                public void addTreeSelectionListener(TreeSelectionListener tsl)

       当用户点击树中某一节点时,将会触发TreeSelectionEvent事件,其所对应的事件监听器接口为TreeSelectionListener,该接口只包含一个方法void valueChanged(TreeSelectionEvent e),在该方法中,可以添加点击树节点所执行的业务逻辑代码。

       在树的创建过程中,可以利用JTree类所提供的getLastSelectedPathComponent()方法可以获取用户当前所选择的节点,该方法的返回值为Object类型,可以将其强制转换为DefaultMutableTreeNode类型。

       当树的结构发生变化时,可以利用DefaultTreeModel类所提供的reload()方法重新加载树结构的数据,使得树的显示与数据的变化保持同步。reload()方法有两种形式:

  • void reload():重新加载整个树结构。
  • void reload(TreeNode node):重新加载指定节点及其子节点的树结构。

       在前面创建树的代码中,用户对象为字符串,而在实际应用中,一般需要自定义用户对象类。为了能够在树节点上显示用户对象类中相应属性的名称,则需要重写该类的toString()方法。例如,下面的代码定义了一个用户对象类Profession,并重写toString()方法,返回name属性的名称。

class Profession{ 
	String code;  //专业代码
	String name;  //专业名称
	public Profession(String code,String name) {
		this.code=code;
		this.name=name;
	}
	//重写方法
	public String toString() {
		return name;
	}
}

【例1】下面的程序演示了如何创建一棵树,主要功能包括增加、插入、修改和删除树节点,以及点击树节点显示其用户对象路径信息。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
public class JTreeDemo extends JFrame{
	JTree tree;  //树
	DefaultTreeModel treeModel;//树的数据模型
	DefaultMutableTreeNode selectedNode;//当前被选择的树节点
	JButton addButton=new JButton("增加");
	JButton insertButton=new JButton("插入");
	JButton updateButton=new JButton("修改");
	JButton deleteButton=new JButton("删除");
	JTextField textField=new JTextField();
	public JTreeDemo() {
		JFrame frame=this;
		this.setTitle("树的示例");
		this.setSize(400, 400);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLocationRelativeTo(null);
		Container contentPane=this.getContentPane();
        //创建树的根节点
		DefaultMutableTreeNode root=new DefaultMutableTreeNode(
                                     new Profession("00","专业"));
		treeModel=new DefaultTreeModel(root);//创建树的数据模型
		tree=new JTree(treeModel);//创建树
		JPanel panel1=new JPanel();
		panel1.setLayout(new FlowLayout(FlowLayout.LEFT));
		panel1.add(addButton);
		panel1.add(insertButton);
		panel1.add(updateButton);
		panel1.add(deleteButton);
		contentPane.add(panel1,BorderLayout.NORTH);
		contentPane.add(new JScrollPane(tree),BorderLayout.CENTER);
		contentPane.add(textField,BorderLayout.SOUTH);
		//注册树的选择事件监听器
		tree.addTreeSelectionListener(new TreeSelectionListener() {
			public void valueChanged(TreeSelectionEvent e) {
				//获取当前被选择的节点
				selectedNode=(DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
				if(selectedNode!=null) {
					//获取当前被选择节点的用户对象路径
					Object userObjects[]=selectedNode.getUserObjectPath();
					String str=userObjects[0].toString();
					for(int i=1;i<userObjects.length;i++) {
						String str1="->"+userObjects[i].toString();
						str+=str1;
					}
					textField.setText(str);
				}
			}
		});
		//增加按钮注册动作事件监听器
		addButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				//获取当前被选择的树节点
				selectedNode=(DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
				if(selectedNode!=null) {
					new TreeNodeDialog(frame,"增加节点",selectedNode);
				}
			}
		});
		//修改按钮注册动作事件监听器
		updateButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				selectedNode=(DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
				if(selectedNode!=null) {
					new TreeNodeDialog(frame,"修改节点",selectedNode);
				}
			}
		});
		//插入按钮注册动作事件监听器
		insertButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				selectedNode=(DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
				if(selectedNode!=null) {
					new TreeNodeDialog(frame,"插入节点",selectedNode);
				}
			}
		});
		//删除按钮注册动作事件监听器
		deleteButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				selectedNode=(DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
				if(selectedNode==root) return;//不能删除根节点
				if(selectedNode!=root && selectedNode!=null) {
					int select=JOptionPane.showConfirmDialog(null, 
                        "是否确定删除?", "删除节点",JOptionPane.YES_NO_OPTION);
					if(select==JOptionPane.YES_OPTION) {
						//获取当前被选择节点的父节点
						DefaultMutableTreeNode parent= 
                               (DefaultMutableTreeNode)selectedNode.getParent();
                        //将当前被选择节点从其父节点中删除
						parent.remove(selectedNode);
						treeModel.reload(parent);//重新加载父节点
					}
				}
			}
		});
		this.setVisible(true);
	}
	//增加和修改树的节点对话框(内部类)
	class TreeNodeDialog extends JDialog{
		JTextField codeField=new JTextField(10);
		JTextField nameField=new JTextField(10);
		JButton saveButton=new JButton("保存");	
		Profession userObject;
		DefaultMutableTreeNode parentNode;
		public TreeNodeDialog(JFrame owner,String title, 
                              DefaultMutableTreeNode selectedNode) {
			super(owner,true);
			this.setTitle(title);
			setSize(300,150);
			setLocationRelativeTo(null);
			setResizable(false);
			JPanel panel1=new JPanel();
			panel1.setLayout(new GridLayout(2,1));
			JPanel panel11=new JPanel();
			JPanel panel12=new JPanel();
			panel11.add(new JLabel("专业代码:"));panel11.add(codeField);
			panel12.add(new JLabel("专业名称:"));panel12.add(nameField);
			panel1.add(panel11);panel1.add(panel12);
			JPanel panel2=new JPanel();
			panel2.add(saveButton);
			add(panel1,BorderLayout.CENTER);
			add(panel2,BorderLayout.SOUTH);
			switch(title) {
			case "增加节点":
			case "插入节点":
				codeField.setText("");
				nameField.setText("");
				break;
			case "修改节点":
				userObject=(Profession)selectedNode.getUserObject();
				codeField.setText(userObject.code);
				nameField.setText(userObject.name);
				break;
			}
			//保存按钮注册动作事件监听器
			saveButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					if(codeField.getText()!="" && nameField.getText()!="") {
						switch(title) {
						case "增加节点":
							//创建新的用户对象
							userObject=new Profession(codeField.getText(), 
                                                      nameField.getText());
							//创建一个新的节点加入到当前被选择节点的子节点数组中
							selectedNode.add(new DefaultMutableTreeNode(userObject));
							break;
						case "插入节点":
							//创建新的用户对象
							userObject=new Profession(codeField.getText(), 
                                                    nameField.getText());
							//获取当前被选择节点的父节点
							parentNode=(DefaultMutableTreeNode)selectedNode.getParent();
							//获取当前被选择节点在其父节点数组中的索引
							int i=parentNode.getIndex(selectedNode);
							//创建一个新的节点插入到当前被选择节点的后面
							parentNode.insert(new 
                                  DefaultMutableTreeNode(userObject), i+1);
							//重新加载parentNode节点
							JTreeDemo.this.treeModel.reload(parentNode);
							break;
						case "修改节点":
							//获取当前被选择节点的用户对象
							userObject=(Profession)selectedNode.getUserObject();
							userObject.code=codeField.getText();
							userObject.name=nameField.getText();	
							break;
						
						}
						//更新加载selectedNode节点
						JTreeDemo.this.treeModel.reload(selectedNode);
					}
				}
			});
			setVisible(true);
		}
	}
	public static void main(String[] args) {
		JTreeDemo frame=new JTreeDemo();
	}
}

       运行上述程序,执行结果如图2(a)所示,初始树中只有一个根节点。当用户选择某一个节点并单击增加按钮后,会弹出增加节点对话框,如图2(b)所示,当用户输入专业代码和专业名称并点击保存按钮后,会在当前被选择节点中增加一个新的子节点。当用户选择某一个节点并单击插入按钮后,会弹出插入插入节点对话框,如图2(c),当用户输入专业代码和专业名称并点击保存按钮后,会在当前被选择节点的后面增加一个新的兄弟子节点。当用户选择某一个节点并单击修改按钮后,会弹出修改节点对话框,如图2(d)所示,用户在该界面中可以修改当前被选择节点的信息。当用户选择某一个节点并单击删除按钮后,会弹出一个确认对话框,询问用户是否删除被选择的节点,如果用户点击“是(Y)”按钮,则会在树中删除以当前被选择节点为根的子树。当用户点击某一结点时,在窗口下方的文本框中会显示从根节点到该节点的名称路径信息。

(a)

(b)

(c)

(d)

图2. 树的使用示例

  • 27
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值