http://blog.csdn.net/kaixinbingju/article/details/8425345
目标: | 1. 掌握JTree应用,树节点的操作; 2. 使用JTree展数,管理对象。 |
1.JTree的创建:
在以上的示例中,我们都是创建默认的Javax.swing.JTree组件,本节就要示例,如何根据我们的需要创建自定义结构的JTree组件。首要明白的概念间:JTree上的节点分为两种,即枝节点和叶节点,其下有叶节点的,就称做枝节点,或称叶节点的父节点。
不论是叶节点,还是枝节点,在代码中,都是表现为一个javax.swing.tree.DefaultMutableTreeNode类的对象,DefaultMutableTreeNode有一个方法,可以将其它的DefaultMutableTreeNode对象加为自己的子节点;还有一个setUserObject(Object obj)和getUserObject方法,用来设定(或取得)节点内保存的对象。
请看如下代码,创建一个简单的树:
//JTree应用示例 public class TestJTree extends javax.swing.JFrame { //程序入口 public static void main(String[] args) { TestJTree tj=new TestJTree(); tj.init(); }
//初始化界面内容 public void init() { this.setTitle("东方标准JTree示例"); this.setSize(300, 400); Java.awt.FlowLayout fl = new java.awt.FlowLayout(); this.setLayout(fl); // 将自己创建的树加到界面上: javax.swing.JTree tree = createTree(); this.add(tree); this.setDefaultCloseOperation(3); this.setVisible(true); } //创建一个自定义树 public javax.swing.JTree createTree() { // 创建默认树 javax.swing.JTree tree = new javax.swing.JTree(); // 首先,创建一个根节点: javax.swing.tree.DefaultMutableTreeNode rootNode = new javax.swing.tree.DefaultMutableTreeNode(); // 设定节点上的数据对象,节点显示标题则为设定对象的toString()值 rootNode.setUserObject("树的测试"); // 树下有5个组: for (int i = 0; i < 5; i++) { DefaultMutableTreeNode teamNode = new DefaultMutableTreeNode(); teamNode.setUserObject("第" + i + "组"); // 将组节点加到根节点上: rootNode.add(teamNode); for (int t = 0; t < 6; t++) { DefaultMutableTreeNode userNode = new DefaultMutableTreeNode(); userNode.setUserObject("第" + t + "个用户"); // 将用户节点加到组节点上: teamNode.add(userNode); } // 创建树的Model对象,创建时传入根节点: javax.swing.tree.DefaultTreeModel dm = new DefaultTreeModel( rootNode); // 将模型设给树,树上显示的将上前面所加载的节点 tree.setModel(dm); // 设定树上的图标 // ImageIcon leafIcon = new ImageIcon("src/budy_init.gif"); // DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); // renderer.setLeafIcon(leafIcon); // tree.setCellRenderer(renderer); } return tree; } } |
JTree创建时,关键的步骤就是:
1. 创建DefaultMutableTreeNode对象,设用其setUserObject设置节点的数据对象,这个节点的标签将显示为所设定(传入)的对象的toString方法返回值;
2. 给DefaultMutableTreeNode对象添加做为子节点的DefaultMutableTreeNode对象;
3. 将第一个,即要做为根节点的DefaultMutableTreeNode对象用来构造一个javax.swing.tree.DefaultTreeModel对象。
4. 将新建的DefaultTreeModel对象set给JTree对象即可。
比较简单吧,跟JMenu的应用方式差不了多少,就是一个一个的向上加。
JTree通常用来展示目录结构型的数据,例如学生管理系统中的分组和每组的学生数据;现在,假设我们要编写一个学生的日志管理系统,将界面用JTree展示:
2.用JTree展示学生日志系统界面:
假设我们要做一个学生日志管理系统:即每个学生每天都要写一篇学习日志,通过我们的程序保存和查看:
1.系统中就必须存在学生对象和每个学生的日志对象;我们首先要编写一个学生类和日志类。
2.系统中一个学生对象可能会有多个日志对象;
3.每个日志对象肯定属于某一个学生对象。
4.通过一个JTree组件展示,JTree上的每个一级节点为一个学生对象,点击后,展示出下面的子节点为用户的日志对象。
经过简单的分析:
学生类必须有的属性:id,name,age
日志类必须有的属性:所属学生的id,title,content,createTime
学生类代码如下:
import java.util.ArrayList; import java.util.List; //学生类定义 public class UserInfo { private int id; private String name; private int age; // 一个学生对象,有属于自己的多个日志对象,在其内部用队列存放 private List<UserBlog> blogList = new ArrayList(); // 为某个学生的日志队列中加入一个日志对象 public void addBlog(UserBlog blog) { blogList.add(blog); } // 取得学生的所有日志对象 public List<UserBlog> getBlogList() { return this.blogList; } // 对应的get/set各属性的方法: public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } |
日志类定义的代码如下(随后的代码中,将省略属性对应的get/set方法):
//日志类定义 public class UserBlog { private int id; private int id_userInfo;// 日志所属学生对象的学生ID private String title; private String content; private String createTime;// 日志创建时间 yyyymmddhh格式 // 一篇日志所属的学生对象 private UserInfo userinfo; // 以下为对应属性的get/set方法. . . |
以上代码需要特别注意的是:学生类在定义时,要考虑到每个学生对象与其日志对象的对应关系,这种关系,可以在设计类时定义好,后面使用时就非常方便:
学生对象与日志对象之间的关系,可以描述为:
1.一个学生对象,有多个日志对象,这是一对多的关系;在学生类定义时,代码体现为:
. . . // 一个学生对象,有属于自己的多个日志对象,在其内部用队列存放 private List<UserBlog> blogList = new ArrayList(); // 为某个学生的日志队列中加入一个日志对象 public void addBlog(UserBlog blog) { blogList.add(blog); } // 取得学生的所有日志对象 public List<UserBlog> getBlogList() { return this.blogList; } . . . |
对于使用UserInfo对象的其它对象而言,只要调用UserInfo对象的getBlogList即可得到这个对象的所有日志对象。
2.每个日志对象,都有自己所属的一个学生对象,这是多对一的关系;UserBlog类中体现为:
. . . private int id_userInfo;// 日志所属学生对象的学生ID private UserInfo userinfo; // 一篇日志所属的学生对象 //得到或设定日志对象所属的UserInfo对象 public UserInfo getUserinfo() { return userinfo; } public void setUserinfo(UserInfo userinfo) { this.userinfo = userinfo; } public int getId_userInfo() { return id_userInfo; } public void setId_userInfo(int id_userInfo) { this.id_userInfo = id_userInfo; } |
在UserBlog类中定义了它所属的UserInfo对象为属性,同时,又定义了它所属的UserInfo对象的id,这看起来是重复了,但这样,会方便后面某些使用这些对象的场景。一般情况下,只要定义一个就行了。
接下来就很简单,我们用程序模拟生成UserInfo和 UserBlog对象,并将其显示到JTree上,首先编写模拟成生用户数据对象的类:
import java.util.ArrayList; import java.util.List; //负责生成模拟数据的类 public class UserDao { //生成模拟的用户对象列表: public List<UserInfo> getAllUser(){ //保存生成的用户对象的列表: List<UserInfo> userList=new ArrayList(); for(int i=0;i<5;i++){//生成5个UserInfo对象 UserInfo us=new UserInfo(); us.setId(i); us.setAge(20+i); us.setName("第"+i+"个学生"); int blogCount=new java.util.Random().nextInt(5)+5;//日志个数的随机数 for(int t=0;t<blogCount;t++){//每个用户生成随机个数的日志对象 UserBlog ub=new UserBlog(); ub.setId(i*t);//每个UserBlog对象的唯一id; ub.setId_userInfo(i);//所属的用户id; ub.setTitle(us.getName()+"的第"+t+"篇日志"); ub.setContent("这是我的日志内容,我将要写"+t+"行"); //程序中生成创建日志的格式化时间 java.util.Date now=new java.util.Date(); java.text.SimpleDateFormat f=new java.text.SimpleDateFormat("yyyy年MM朋dd日hh:mm:ss"); String timeStr=f.format(now); ub.setCreateTime(timeStr); ub.setUserinfo(us);//日志对象所属的用户对象 //将这个日志对象装入所属用户对象的列表中: us.addBlog(ub); } //将生成的us对象放入到队列中 userList.add(us); } return userList; } } |
UserDao中只有一个方法,当这个方法调用时,生成模拟的用户对象和blog对象(在具体的应用中,这个方法应是从数据库或文件中提取数据,生成对象)。
最后,我们编写界面代码:显示一个JTree对象,JTree中的节点对应了UserInfo和UserBlog对象:
//JTree应用示例:简单日志管理系统
public class BlogManagerUI extends javax.swing.JFrame {
public static void main(String[] args) {
BlogManagerUI tj=new BlogManagerUI();
tj.init();
}
//初始化界面内容
public void init() {
this.setTitle("东方标准JTree示例--日志管理");
this.setSize(300, 400);
java.awt.FlowLayout fl = new java.awt.FlowLayout();
this.setLayout(fl);
//创建用户列表后,就可以使用userList中的对象构造树:
UserDao dao=new UserDao();
userList=dao.getAllUser();
// 将自己创建的树加到界面上:
javax.swing.JTree tree = createTree();
this.add(tree);
this.setDefaultCloseOperation(3);
this.setVisible(true);
}
//创建一个自定义树
public javax.swing.JTree createTree() {
// 创建默认树
javax.swing.JTree tree = new javax.swing.JTree();
// 首先,创建一个根节点:
javax.swing.tree.DefaultMutableTreeNode rootNode = new javax.swing.tree.DefaultMutableTreeNode();
// 设定节点上的数据对象,节点显示标题则为设定对象的toString()值
rootNode.setUserObject("日志管理");
//取得要加载到树上的用户对象列表
for (int i = 0; i <userList.size(); i++) {
DefaultMutableTreeNode teamNode = new DefaultMutableTreeNode();
//得到列表中每一个用户对象,设为树节点对象
UserInfo us=userList.get(i);
teamNode.setUserObject(us);
// 将组节点加到根节点上:
rootNode.add(teamNode);
//取得所属于这个用户的blog对象列表
List<UserBlog> blogList=us.getBlogList();
for (int t = 0; t <blogList.size(); t++) {
DefaultMutableTreeNode userNode = new DefaultMutableTreeNode();
UserBlog ub=blogList.get(t);//从队列中得到blog对象
userNode.setUserObject(ub);
// 将用户节点加到组节点上:
teamNode.add(userNode);
}
// 创建树的Model对象,创建时传入根节点:
javax.swing.tree.DefaultTreeModel dm = new DefaultTreeModel(rootNode);
// 将模型设给树,树上显示的将上前面所加载的节点
tree.setModel(dm);
}
return tree;
}
//用户对象列表:
private List<UserInfo> userList;
}
接下来,我们应该给JTree加上弹出菜单实现Tree上节点对应对象的删改功能。
3.JTree节点的选中和信息获取
在弹出菜单示例的那一节,我们己知道如何给组件加上弹出菜单,在这个基础上,要实现的就是当菜单事件发生时,实现对应的功能操作:从树上移除,增加或显示选中节点所含的对象的数据;并更新内存中UserInfo对象列表中的数据。首先,我们实现能显示用户选中的节点的数据对象:
import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; //JTree应用示例:简单日志管理系统 public class BlogManagerUIV1 extends javax.swing.JFrame { public static void main(String[] args) { BlogManagerUIV1 tj=new BlogManagerUIV1(); tj.init(); } //初始化界面内容 public void init() { this.setTitle("东方标准JTree示例--日志管理"); this.setSize(300, 400); java.awt.FlowLayout fl = new java.awt.FlowLayout(0); this.setLayout(fl); //创建用户列表后,就可以使用userList中的对象构造树: UserDao dao=new UserDao(); userList=dao.getAllUser(); tree = createTree(); javax.swing.JPopupMenu pop=createPopMenu();//设定树上的弹出菜单: tree.setComponentPopupMenu(pop); this.add(tree); // 将自己创建的树加到界面上: this.setDefaultCloseOperation(3); this.setVisible(true); } //创建一个自定义树 public javax.swing.JTree createTree() { javax.swing.JTree tree = new javax.swing.JTree();// 创建默认树 // 首先,创建一个根节点: javax.swing.tree.DefaultMutableTreeNode rootNode = new javax.swing.tree.DefaultMutableTreeNode(); // 设定节点上的数据对象,节点显示标题则为设定对象的toString()值 rootNode.setUserObject("日志管理"); //取得要加载到树上的用户对象列表 for (int i = 0; i <userList.size(); i++) { DefaultMutableTreeNode teamNode = new DefaultMutableTreeNode(); //得到列表中每一个用户对象,设为树节点对象 UserInfo us=userList.get(i); teamNode.setUserObject(us); rootNode.add(teamNode); // 将组节点加到根节点上 //取得所属于这个用户的blog对象列表 List<UserBlog> blogList=us.getBlogList(); for (int t = 0; t <blogList.size(); t++) { DefaultMutableTreeNode userNode = new DefaultMutableTreeNode(); UserBlog ub=blogList.get(t);//从队列中得到blog对象 userNode.setUserObject(ub); teamNode.add(userNode); // 将用户节点加到组节点上 } // 创建树的Model对象,创建时传入根节点: javax.swing.tree.DefaultTreeModel dm = new DefaultTreeModel(rootNode); // 将模型设给树,树上显示的将上前面所加载的节点 tree.setModel(dm); } return tree; } //创建弹出菜单 private javax.swing.JPopupMenu createPopMenu(){ //创建弹出菜单对象 javax.swing.JPopupMenu popMenu=new javax.swing.JPopupMenu(); //1创建文件菜单下的菜单项: javax.swing.JMenuItem mi_open=new javax.swing.JMenuItem("添加"); mi_open.setActionCommand("add");//设置菜单的命令关键字 javax.swing.JMenuItem mi_new=new javax.swing.JMenuItem("删除"); mi_new.setActionCommand("del"); javax.swing.JMenuItem mi_exit=new javax.swing.JMenuItem("修改"); mi_exit.setActionCommand("mod"); //创建内部料的菜单事件监听器对象 java.awt.event.ActionListener ac_listener=new java.awt.event.ActionListener(){ public void actionPerformed(ActionEvent e){ treeMenuAction(e);//调用统一的处理方法: } }; //2 给菜单项加上事件监听器: mi_open.addActionListener(ac_listener); mi_new.addActionListener(ac_listener); mi_exit.addActionListener(ac_listener); //3 将菜单项加到弹出菜单对象上: popMenu.add(mi_open); popMenu.add(mi_new); popMenu.add(mi_exit); return popMenu; } //响应树上的弹出菜单事件 private void treeMenuAction(ActionEvent e){ String command=e.getActionCommand();//得到选中菜单的命令 //得到在树上选中的路径 javax.swing.tree.TreePath tp=tree.getSelectionPath(); //如果选中了树上的某个节点: if(null!=tp){ ///得到选中的节点,每个节点都是DefaultMutableTreeNode对象 DefaultMutableTreeNode selectNode=(DefaultMutableTreeNode)tp.getLastPathComponent(); //取得选中节点内的对象,即setUserObject传入的对象 Object userObject=selectNode.getUserObject(); //判断是何种对象 if(userObject instanceof UserInfo){//选中用户节点 UserInfo user=(UserInfo)userObject;//强制转型 String s="要执行的操作是 "+command; String info="用户信息:用户id:"+user.getId()+" 用户名 "+user.getName(); javax.swing.JOptionPane.showMessageDialog(this,s+"/r/n"+info); } if(userObject instanceof UserBlog){//选中日志节点 UserBlog blog=(UserBlog)userObject;//强制转型 String s="要执行的操作是 "+command; String info="Blog信息:Blog id:"+blog.getId()+" 标题:"+blog.getTitle(); javax.swing.JOptionPane.showMessageDialog(this,s+"/r/n"+info); } }else{ javax.swing.JOptionPane.showMessageDialog(this,"请选中树上的节点!"); } } javax.swing.JTree tree ;//界面上显示的树的名字 private List<UserInfo> userList; //用户对象列表 } |
以上代码,关键是在弹出菜单的事件处理中:当用户选中菜单时,得要选中的树上的节点,并取得这个节点所代表的对象,通过instanceof关键字比较,选中的是UserInfo对象的节点还是UserBlog对象的节点;在本例中,仅是将用户要执行的操作命令和选中对象的部分数据显示出来而己
接下来,我们就应真正的实现菜单上的功能:
4.JTree的编辑《日志管理实现》:
在上例中,我们己可以得到选中的节点对象和节点内部的数据对象,接下来,要实现的是当选删除菜单时,将选中的节点从树上移掉;当点击添加和修改菜单时,应能弹出界面让用户实现修改和添加功能。请看如下代码:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
//JTree应用示例:简单日志管理系统
public class BlogManagerUIV2 extends javax.swing.JFrame {
//主界面:初始化时创建,因为要在内部类中使用,要定义为final型
private static final BlogManagerUIV2 mainUI=new BlogManagerUIV2();
public static void main(String[] args) {
mainUI.init();
}
//初始化界面内容
public void init() {
this.setTitle("东方标准JTree--日志管理v2");
this.setSize(300, 400);
java.awt.FlowLayout fl = new java.awt.FlowLayout(0);
this.setLayout(fl);
//调用模拟生成数据的对象方法,得到UserInfo对象列表
UserDao dao=new UserDao();
List<UserInfo> userList =dao.getAllUser();
//根据传入的用户列表对象,调用创建树的方法,在createTree方法中创建树上的节点
javax.swing.JTree tree = createTree(userList);
//设定树上的弹出菜单,并在createPopMenu方法中实现菜单事件
javax.swing.JPopupMenu pop=createPopMenu(tree);
tree.setComponentPopupMenu(pop);//指定树上的弹出菜单
this.add(tree);//将创建好的树加到界面上
this.setDefaultCloseOperation(3);
this.setVisible(true);
}
/**
* 根据传入的UserInfo对象列表创建树上的节点
* 1.列表中每个UserInfo对象是一个枝节点;
* 2.每个UserInfo对象对象的多个UserBlog对象为其叶节点
* @param userList:装有UserInfo对象的列表
* @return :创建好的树
*/
public javax.swing.JTree createTree(List<UserInfo> userList) {
final javax.swing.JTree tree = new javax.swing.JTree();// 创建默认树
// 首先,创建一个根节点:
javax.swing.tree.DefaultMutableTreeNode rootNode = new javax.swing.tree.DefaultMutableTreeNode();
// 设定节点上的数据对象,节点显示标题则为设定对象的toString()值
rootNode.setUserObject("日志管理");
//取得要加载到树上的用户对象列表
for (int i = 0; i <userList.size(); i++) {
DefaultMutableTreeNode teamNode = new DefaultMutableTreeNode();
UserInfo us=userList.get(i); //得到列表中每一个用户对象,设为树节点对象
teamNode.setUserObject(us); // 将组节点加到根节点上
rootNode.add(teamNode);
//取得所属于这个用户的blog对象列表
List<UserBlog> blogList=us.getBlogList();
for (int t = 0; t <blogList.size(); t++) {
DefaultMutableTreeNode userNode = new DefaultMutableTreeNode();
UserBlog ub=blogList.get(t);//从队列中得到blog对象
userNode.setUserObject(ub);
teamNode.add(userNode); // 将用户节点加到组节点上
}
// 创建树的Model对象,创建时传入根节点:
javax.swing.tree.DefaultTreeModel dm = new DefaultTreeModel(rootNode);
// 将模型设给树,树上显示的将上前面所加载的节点
tree.setModel(dm);
}
return tree;
}
/**
* 创建传入的JTree对象上的弹出菜单,并指定事件处理
* @param tree:弹出菜单所在的树对象
* @return:创建好的弹出菜单对象
*/
private javax.swing.JPopupMenu createPopMenu(final JTree tree){
//创建弹出菜单对象
javax.swing.JPopupMenu popMenu=new javax.swing.JPopupMenu();
//1创建文件菜单下的菜单项:
javax.swing.JMenuItem mi_open=new javax.swing.JMenuItem("添加");
mi_open.setActionCommand("add");//设置菜单的命令关键字
javax.swing.JMenuItem mi_new=new javax.swing.JMenuItem("删除");
mi_new.setActionCommand("del");
javax.swing.JMenuItem mi_exit=new javax.swing.JMenuItem("修改");
mi_exit.setActionCommand("mod");
//创建内部类的菜单事件监听器对象:
java.awt.event.ActionListener ac_listener=new java.awt.event.ActionListener(){
public void actionPerformed(ActionEvent e){
//当事件发生时,调用事件处理方法
treeMenuAction(e,tree);
}
};
//2 给菜单项加上事件监听器:
mi_open.addActionListener(ac_listener);
mi_new.addActionListener(ac_listener);
mi_exit.addActionListener(ac_listener);
//3 将菜单项加到弹出菜单对象上:
popMenu.add(mi_open);
popMenu.add(mi_new);
popMenu.add(mi_exit);
return popMenu;
}
/**
* 响应树上的弹出菜单事件
* 1.当点击菜单时选中的树节点是代表UserInfo对象时调用changeUserInfo方法
* 2.当点击菜单时选中的树节点是代表BlogInfo对象时调用chageBlogInfo方法
* @param e :事件对象
* @param tree :事件发生所在的树
*/
private void treeMenuAction(ActionEvent e,JTree tree){
String command=e.getActionCommand();//得到选中菜单的命令
//得到在树上选中的路径
javax.swing.tree.TreePath tp=tree.getSelectionPath();
//如果选中了树上的某个节点:
if(null!=tp){
///得到选中的节点,每个节点都是DefaultMutableTreeNode对象
DefaultMutableTreeNode selectNode=(DefaultMutableTreeNode)tp.getLastPathComponent();
//取得选中节点内的对象,即setUserObject传入的对象
Object userObject=selectNode.getUserObject();
//判断是何种对象
if(userObject instanceof UserInfo){//选中用户节点
UserInfo user=(UserInfo)userObject;//强制转型
//调用处理方法,传入命令字和要处理的对象
changeUserInfo(command,user,selectNode);
}
if(userObject instanceof UserBlog){//选中日志节点
UserBlog blog=(UserBlog)userObject;//强制转型
//调用处理方法,传处命令字和要处理的对象
chageBlogInfo(command,blog,selectNode);
}
}else{
javax.swing.JOptionPane.showMessageDialog(this,"请选中树上的节点!");
}
}
//处理对树上UserInfo节点选中的事件
private void changeUserInfo(String command,UserInfo user,DefaultMutableTreeNode selectNode){
if(command.equals("del")){
//让用户确认
int i=javax.swing.JOptionPane.showConfirmDialog(this, "确认要移除吗?");
if(i==0){//确认框返架结果如为0,表示确认del
selectNode.removeFromParent();
javax.swing.SwingUtilities.updateComponentTreeUI(this);
}
}
else if(command.equals("add")||command.equals("mod")){
showAddOrModifyUserInfoDialog(command,user,selectNode);
}
}
//处理树上UserBlog对象选中的事件
private void chageBlogInfo(String command,UserBlog blog,DefaultMutableTreeNode selectNode){
if(command.equals("del")){
//让用户确认
int i=javax.swing.JOptionPane.showConfirmDialog(this, "确认要移除吗?");
if(i==0){//确认框返架结果如为0,表示确认del
selectNode.removeFromParent();
javax.swing.SwingUtilities.updateComponentTreeUI(this);
}
}
else if(command.equals("add")||command.equals("mod")){
showAddOrModifyBlogDialog(command,blog,selectNode);
}
}
//显示添加/修改blog的对话话,并实现事件响应
private void showAddOrModifyBlogDialog(final String command,final UserBlog blog,final DefaultMutableTreeNode selectNode){
//创建并弹出对话框,显示输入组件,
final javax.swing.JDialog jda=new javax.swing.JDialog();
java.awt.FlowLayout fl=new java.awt.FlowLayout();
jda.setLayout(fl);
jda.setSize(this.getWidth(),this.getHeight()/2);
jda.setModal(true); //设置为"模型"对话框
javax.swing.JLabel la_title=new javax.swing.JLabel("日志标题:");
final javax.swing.JTextField jta_title=new javax.swing.JTextField(15);
javax.swing.JLabel la_content=new javax.swing.JLabel("日志内容:");
final javax.swing.JTextArea jta_content=new javax.swing.JTextArea(5,15);
jda.add(la_title);
jda.add(jta_title);
jda.add(la_content);
jda.add(jta_content);
javax.swing.JButton bu_blog=new javax.swing.JButton();
//根据不同的操作,设定对话框按钮上的标签
if(command.equals("add")){
jda.setTitle("用户"+blog.getUserinfo().getName()+"添加一篇日志");
bu_blog.setText("添加");
}else if(command.equals("mod")){
jda.setTitle("修改日志");
bu_blog.setText("修改");
//将节点中所含对象的信息显示到界面上:
jta_title.setText(blog.getTitle());
jta_content.append(blog.getContent());
}
jda.add(bu_blog);
添加对话框上的按钮的事件处理器
bu_blog.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
String title=jta_title.getText();//得到用户输入的内容
String content=jta_content.getText();
if(command.equals("add")){//如果是添加命令
UserBlog nb=new UserBlog();//根据输入内容创建blog对象
nb.setId(1);
nb.setTitle(title);
nb.setContent(content);
nb.setUserinfo(blog.getUserinfo());
blog.getUserinfo().addBlog(nb);//加给对应的用户对象内
//创建新节点
DefaultMutableTreeNode dm=new DefaultMutableTreeNode();
dm.setUserObject(nb);
//得到己选中节点的父节点,将根据用户输入新建的节点加到树上:
DefaultMutableTreeNode parent=(DefaultMutableTreeNode)selectNode.getParent();
parent.add(dm);
}
if(command.equals("mod")){//如果是修改命令:
//重新设定原来选中的节点所代表的blog对象的标题和内容:
blog.setTitle(title);
blog.setContent(content);
}
jda.dispose();//关闭对话框
//刷新界面,否则树上显示不了!
javax.swing.SwingUtilities.updateComponentTreeUI(mainUI);
}
});
jda.setVisible(true);
}
//显示添加/修改UserInfo的对话话,并实现事件响应
private void showAddOrModifyUserInfoDialog(final String command,final UserInfo user,final DefaultMutableTreeNode selectNode){
//修改或新建时,弹出一个Jdialog(对话框,类似于JFrame)对象
final javax.swing.JDialog jda=new javax.swing.JDialog();
java.awt.FlowLayout fl=new java.awt.FlowLayout();
jda.setLayout(fl);
jda.setSize(this.getWidth(),this.getHeight()/2);
jda.setModal(true);
javax.swing.JLabel la_name=new javax.swing.JLabel("用户名:");
final javax.swing.JTextField jta_name=new javax.swing.JTextField(15);
javax.swing.JLabel la_age=new javax.swing.JLabel("用户年令:");
final javax.swing.JTextField jta_age=new javax.swing.JTextField(5);
jda.add(la_name);
jda.add(jta_name);
jda.add(la_age);
jda.add(jta_age);
javax.swing.JButton bu_blog=new javax.swing.JButton();
if(command.equals("add")){//如果是添加命令
jda.setTitle("添加一个用户信息");
bu_blog.setText("添加");
}else if(command.equals("mod")){
jda.setTitle("修改用户信息");
bu_blog.setText("修改");
//将节点中所含对象的信息显示到界面上:
jta_name.setText(user.getName());
jta_age.setText(""+user.getAge());//用户年令是设定到界面上必须是字符
}
jda.add(bu_blog);
bu_blog.addActionListener(new ActionListener(){//添加对话框上的事件执行
public void actionPerformed(ActionEvent e){
String name=jta_name.getText();//得到用户输入的内容
String str_age=jta_age.getText();
//将从界面上得到的年令串转为int型:
int age=Integer.parseInt(str_age);
if(command.equals("add")){//如果是添加命令
UserInfo newUser=new UserInfo();//根据输入内容创建blog对象
newUser.setId(1);
newUser.setAge(age);
newUser.setName(name);
//创建新节点,代表新建的用户对象
DefaultMutableTreeNode newUserNode=new DefaultMutableTreeNode();
newUserNode.setUserObject(newUser);
//得到己选中节点的父节点,将根据用户输入新建的节点加到树上:
DefaultMutableTreeNode parent=(DefaultMutableTreeNode)selectNode.getParent();
parent.add(newUserNode);
//第一个新建的用户,要为其建一个blog对象
UserBlog nb=new UserBlog();
nb.setId(1);
nb.setTitle("默认日志");
nb.setContent("默认内容");
nb.setUserinfo(newUser);
newUser.addBlog(nb);//加给对应的用户对象内
//创建新节点
DefaultMutableTreeNode dmBlog=new DefaultMutableTreeNode();
dmBlog.setUserObject(nb);
//将给这个新用户默认的新日志对象做为一个节点加到新用户对象代表的节点下:
newUserNode.add(dmBlog);
}
if(command.equals("mod")){//如果是修改命令:
//重新设定原来选中的节点所代表的UserInfo对象的标题和内容:
user.setAge(age);
user.setName(name);
}
jda.dispose();//处理完毕后,关闭对话框
//刷新界面,否则树上显示不了!
javax.swing.SwingUtilities.updateComponentTreeUI(mainUI);
}
});
jda.setVisible(true);
}
}
5.完善分析
必须明白的一个问题是:简单的功能是谁都可以实现的,但精致、完美是无至境的。上面的示例实现的简单的功能,但还有很大缺陷:
1. 用户的输入没有较验,如新建UserInfo对象时,如用户不输出信息,就点了保存按钮,程序就出会错而没有给用户友好的提示。这点我想你可以自己完成!
2. 界面上通常需要用户输入固定格式的内容,如年令必须是数字---我们编程时可以指定这一点---如果程序给了用户犯错的机会,那是程序员的错!
如下代码示例如何格式化输入:
public static void main(String args[]) {
JFrame f = new JFrame("格式化输出测试");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
java.awt.FlowLayout fl = new java.awt.FlowLayout();
f.setLayout(fl);
// 日期格式输入
DateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
DateFormatter df = new DateFormatter(format);
final JFormattedTextField ft_date = new JFormattedTextField(df);
ft_date.setValue(new Date());
f.add(ft_date);
MaskFormatter ip_mf = null; // IP地址(都是数字)格式输入
MaskFormatter ip_age = null; // 年令格式
try {
ip_mf = new MaskFormatter("###-###-###-###");
ip_mf.setPlaceholderCharacter('_');// 加上占位符
ip_age = new MaskFormatter(" ## ");
} catch (Exception ef) {
ef.printStackTrace();
}
final JFormattedTextField ft_ipAdd = new JFormattedTextField(ip_mf);
f.add(ft_ipAdd);
//输入数字,做为年令
final JFormattedTextField ft_age = new JFormattedTextField(ip_age);
f.add(ft_age);
// 创建一个事件监听器
ActionListener acton = new ActionListener() {
public void actionPerformed(ActionEvent e) {
String date = ft_date.getText();
String ipadd = ft_ipAdd.getText();
//得到年令输入框中的值,并去掉前后的空格
int age=Integer.parseInt(ft_age.getText().trim());
String msg = "生日: " + date + "/r/n IP地址: " + ipadd
+ "/r/n 年令: " + age;
javax.swing.JOptionPane.showMessageDialog(null, msg);
}
};
// 给输入框加上监听器当按下回车弹出消息框显示输入值,如输入不正确,则不会弹出!!!
// ft_date.addActionListener(acton);
// ft_ipAdd.addActionListener(acton);
ft_age.addActionListener(acton);
f.setSize(300, 100);
f.setVisible(true);
}
特别要注意的是:格式化输入时,如果用户输入内容不足,事件将不出发生。
1. 程序启动时,窗口第一次出现的位置总是在左上角,这不符合使用习惯,应当让它初始显示在屏的正中。如下代码所示,窗口初始化显示在屏的右下方:
public static void main(String args[]) { JFrame f = new JFrame("初始化窗口显示位置测试--显在屏右下"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //取得屏幕大小对象:dm的getWidth和getHeight返回屏幕的宽和高的double型值 java.awt.Dimension dm=java.awt.Toolkit.getDefaultToolkit().getScreenSize(); int sc_width=(int)dm.getWidth(); int sc_heigth=(int)dm.getHeight(); //组件对象的getWidth和getHeight方法得到自身的宽和高,int型 //组件的setLocation设置组件所处位置的x,y坐标: f.setLocation((sc_width-f.getWidth())/2,(sc_heigth-f.getHeight())/2); f.setSize(300, 100); f.setVisible(true); } |
你来改正?让我们的blog管理程序初始显示在屏的正中!
2. 界面功能的改进:
树形结构,一般用做导航的功能,就像操作系统的资源管理器打开时一样;具体数据的展示,如本例中,用户信息和用户的blog信息,应当放在JTable中展示,这样才符合常规;并且,完整的界面,应当还有菜单条和工具栏;请想想还有哪些不足,你还可改进哪些?在下一节,我们掌握如何在应用中结合使用JTree和JTable:使用JTree导航,使用JTable展示数据。
总结和任务:
3.实践:自己编写树,实现简单的管理功能(如管理学生和学生的日志对象分别为枝节点和叶节点、管理部门和部门的员工对象分别为枝节点和叶节点. . .)。
4.总结:JTree使用总结: