第三节:高级Swing界面JTable编程
目标: | 1. 掌握表格组件的基本用法; 2. 理解数据结构与界面分离的设计原理 |
3.使用JTable+TableModel展示java中的数据对象: 4
1.JTable与TableModel
1.TableModel与JTable的关系:
前面,我们己学会在界面上加入一个简单的JTable对象:
JTable table=new JTable(3,5);这段代码即可创建一个三行五列的表格用以显示在界面上;在具体的应用中,我们肯定是要让JTable显示我们自己定义的数据,比如将上例中的UserInfo对象或UserBlog对象显示到表格中,那就必须定制JTable对象所要使用的javax.swing.table.TableModel对象,在开始前,我们先理解javax.swing.table.TableModel和JTable之间的关系:模特与衣服之间的关系:
JTable对象---------->TableModel
简单的说,JTable只是一个界面,主要负责显示功能,但JTable对象具体显示多少行多少列,甚示每行每列中显示什么类型的数据,JTable中的单元格是否可编辑,编辑之后怎么办…关于数据提供和数据操作的实现,都是由这个JTable对象的TableModel对象所负责的;反向而言,当JTable对象界面的数据被改动时,JTable会自动调用自己模型中的方法将改动反映到模型中。
说了这么多,我们来看TableModel到底是什么东东----它是一个接口定义,源码说明如下:
//通过调用JTable对象的setModel方法,传入实现了TableModel接口类的对象 public interface TableModel{ public int getRowCount();//决定表格上显示多少行 public int getColumnCount();//表格上显示多少列 //得到某一列的列名,columnIndex:列的序号,从0开始 public String getColumnName(int columnIndex); //得到某一列的数据类型,columnIndex:列的序号,从0开始 public Class<?> getColumnClass(int columnIndex); //某一单元格在界面上是否可直接编辑,rowIndex:行号,columnIndex:列号,从0开始 public boolean isCellEditable(int rowIndex, int columnIndex); //具体的JTable在显示时,调用这个方法取得每一个一单元格的值 public Object getValueAt(int rowIndex, int columnIndex); //如果表格可编辑,表格对象将调用这个方法将改变后的值反映到它的model对象中 //aValue代表修改后的值,rowIndex,columnIndex表示所在的行列索引。 public void setValueAt(Object aValue, int rowIndex, int columnIndex); //模型对象可调用这个方法为自己加入一个监听器 public void addTableModelListener(TableModelListener l); //移除模型对象中的监听器 public void removeTableModelListener(TableModelListener l); } |
根据以上接口定义,我们只需要编写一个实现了TableModel的类,通过如下样例代码:javax.swing.JTable table=new javax.swing.JTable();
table.setModel(new 实现了TableModel接口的类);
就可以在JTable对象在显示时,就会自动调用传入的Model中的方法用以填充自己的单元格的数据。
2.TableModel实践:
首先,我们编写一个TableModel的实现类如下:
import javax.swing.event.TableModelListener; /**自定义的tableModel实现类*/ public class MyTableModelV1 implements javax.swing.table.TableModel{ //多少行: public int getRowCount(){ return 10; } //多少列 public int getColumnCount(){ return 5; } //取得列名 public String getColumnName(int columnIndex){ return " 第"+columnIndex+"列名"; } //每一列的数据类型:我们这里显示的都是String型 public Class<?> getColumnClass(int columnIndex){ return String.class; } //指定的单元格是否可从界面上编辑 public boolean isCellEditable(int rowIndex, int columnIndex){ if(columnIndex==0){ return false; } return true; } //取得指定单元格的值 public Object getValueAt(int rowIndex, int columnIndex){ return rowIndex+"--"+columnIndex; } //从表格界面上改变了某个单元格的值后会调用这个方法 public void setValueAt(Object aValue, int rowIndex, int columnIndex){ String s="Change at: "+rowIndex+"--- "+columnIndex+" newValue: "+aValue; System.out.println(s); } //这两个接口方法暂无用 public void addTableModelListener(TableModelListener l){} public void removeTableModelListener(TableModelListener l){} } |
使用这个TableModel对象的JTable将显示10行5列,每个单元格将返回getValueAt方法返回的字符串,当我们在使用它的表格界面上编辑表格数据(第一列不可编辑,Model中限定了),就会调用setValue方法将编辑过后的值打印出来。
用以显示这个Model的Jtable和界面代码如下:
//TableModel应用测试 public class TestJTable { //程序入口 public static void main(String[] args) { javax.swing.JFrame jf=new javax.swing.JFrame("表格测试"); jf.setSize(300,400); java.awt.FlowLayout fl=new java.awt.FlowLayout(); jf.setLayout(fl); //1.创建一个默认的简单表格对像: javax.swing.JTable table=new javax.swing.JTable(); //2.创建我们自定义的TableModel对象 MyTableModelV1 tm=new MyTableModelV1(); //3.将其设置为Table的Model table.setModel(tm); jf.add(table); jf.setDefaultCloseOperation(3); jf.setVisible(true); } } |
要让某个JTable对象按照我们自己实现的TableModel显示数据,只需要创建我们实现的TableModel的对象:
MyTableModelV1 tm=new MyTableModelV1();
然后调用JTable对象的setModel方法,传入自定义的TableModel对象即可
3.使用JTable+TableModel展示java中的数据对象:
具体请看示例,将多个UserInfo对象列表的数据显示到JTable中,首先,我们需要编写自己的TableModel类,即实现了javax.swing.table.JtableModel接口的类,这个实现类使用装有UserInfo的List对象,负责将列表中的用户对象信息提供给Jtable对象显示:
import java.util.List; import javax.swing.event.TableModelListener; import javax.swing.table.TableModel; /** * 用以在JTable中显示UserInfo对象的TableModel实现类 * */ public class UserInfoTableModel implements TableModel{ private List<UserInfo> userList; //要显示的UserInfo对象列表 //创建模型对象时,必须传入要显示的UserInfo对象列表 public UserInfoTableModel(List<UserInfo> userList){ this.userList=userList; } //得到行数:列表中有几个UserInfo对象,就显示几行 public int getRowCount(){ return userList.size(); } //得到列数,UserInfo对象的每个属性是一列,id,name,age,共3列 public int getColumnCount(){ return 3; } //指定某列的类型:暂时都是字符串类型, public Class<?> getColumnClass(int columnIndex){ return String.class; } //得到指定单元格的值:第几行,就是列表中的第几个UserInfo对象 public Object getValueAt(int rowIndex, int columnIndex){ // 第几行,就是列表中的第几个UserInfo对象 UserInfo user=userList.get(rowIndex); if(columnIndex==0){//第一列是UserInfo对象的id值 return ""+user.getId(); }else if(columnIndex==1){//第二列是name属性值 return user.getName(); }else if(columnIndex==2){//第二列是age值 return ""+user.getAge(); }else{//除非设计时逻辑错误,否则不会到这里 return "出错!"; } } //界面数据有变化时,模型对象的这个方法会被调用,暂时弹出说明框 public void setValueAt(Object aValue, int rowIndex, int columnIndex){ String info=rowIndex+"行"+columnIndex+"列的值改变: "+aValue.toString(); javax.swing.JOptionPane.showMessageDialog(null,info); } //指定某单元格是否可编辑:第一列不可编缉,第一列是ID,是每个对象的唯一识别号 public boolean isCellEditable(int rowIndex, int columnIndex){ if(columnIndex!=0){ return true; } return false; } //取每一列的列名 public String getColumnName(int columnIndex){ if(columnIndex==0){//第一列是UserInfo对象的id值 return "序 号"; }else if(columnIndex==1){//第二列是name属性值 return "姓 名"; }else if(columnIndex==2){//第二列是age值 return "年 令"; }else{//除非设计时逻辑错误,否则不会到这里 return "出错!"; } } //添加和移除监听器的方法暂不用,写为空的 public void addTableModelListener(TableModelListener l){} public void removeTableModelListener(TableModelListener l){} } |
接下来,我们创建界面和JTable对象,使用我们新编写的UserInfoTableModel对象显示用户数据。
/** * JTable和TableModel使用示例 v1 * */ public class UserTableUIV1 { //程序入口 public static void main(String[] args) { UserTableUIV1 lu=new UserTableUIV1(); lu.setupUI(); } //显示主界面 public void setupUI(){ javax.swing.JFrame jf=new javax.swing.JFrame("JTable-TableModel示例"); jf.setSize(300,200); java.awt.FlowLayout fl=new java.awt.FlowLayout(); jf.setLayout(fl); //创建一个表格对象 final javax.swing.JTable table=new javax.swing.JTable(); //得到要显示的用户列表对象: List<UserInfo> userList=getUserList(); //创建我们实现的TableModel对象,创建时要传入用户列表对象 UserInfoTableModel tm=new UserInfoTableModel(userList); table.setModel(tm);//将模型设给表格 jf.add(table); jf.setDefaultCloseOperation(3); jf.setVisible(true); } //模拟生成用户对象列表 private List<UserInfo> getUserList(){ List<UserInfo> uList=new ArrayList(); for(int i=0;i<100;i++){ UserInfo user=new UserInfo(); user.setId(i+1); user.setAge(20+i); user.setName("用户"+i); uList.add(user); } return uList; } } |
关于JTable和TableModel对象,一定要体会的就是“衣服”和“模特”之间的关系,呵呵;当我们在界面上修改了JTable中的值,模型对象中的方法就会被调用。
但这个JTable看起来一点也不漂亮,表格的标题头也没显示出来,接下来,我们美化一下,现在美化JTable,与模型,即数据模型没关系,就像要改衣服,不用动模特一样:
2.JTable展示方式的美化:
1.设置表格的宽度和高度:
如下代码示例:
//设每一列的宽度 for(int i=0;i<table.getColumnCount();i++){ table.getColumnModel().getColumn(i).setPreferredWidth(40); } table.setRowHeight(20);//设定每一列的高度 |
2.要显示表头:
要将Jtable放到滚动板(javax.swing.JscrollPane)上,并设定其大小:
使用如下代码段,:
//将表格对象放到滚动面板对象上 javax.swing.JScrollPane scrollPane = new JScrollPane(table); //设定表格在面板上的大小 table.setPreferredScrollableViewportSize(new Dimension(200, 70)); //超出大小后,JScrollPane自动出现滚动条 scrollPane.setAutoscrolls(true); jf.add(scrollPane);//将scrollPane对象加到界面上 |
3.新加列,将列设为下拉框:
代码示例:
table.addColumn(new TableColumn(3)); //创建下拉框对象,并设定其中的值 JComboBox c = new JComboBox(); c.addItem("长沙"); c.addItem("株州"); c.addItem("湘潭"); c.setSelectedIndex(0); //将下拉框设为表格的单元格: table.getColumnModel().getColumn(3).setCellEditor(new DefaultCellEditor(c)); |
4.表格排序:
排序要实现的功能是,当单击表头时,所在列会自动排序,代码段如下:
RowSorter<javax.swing.table.TableModel> sorter = new TableRowSorter<TableModel>(table.getModel()); table.setRowSorter(sorter); |
3. JTable事件响应和项目设想
JTable事件响应是非常简单,如下代码片断所示,我们可以给表格加上一个鼠标事件监听器,当鼠标单击表格(上的某一个单元格)时,弹出单元格所在的行表和单元格中的值:
//给table加上一个鼠标事件监听器对象 table.addMouseListener(new java.awt.event.MouseAdapter(){ public void mouseClicked(MouseEvent e) {//仅当鼠标单击时响应 //得到选中的行列的索引值 int r= table.getSelectedRow(); int c= table.getSelectedColumn(); //得到选中的单元格的值,表格中都是字符串 Object value= table.getValueAt(r, c); String info=r+"行"+c+"列 值 : "+value.toString(); javax.swing.JOptionPane.showMessageDialog(null,info); } });
表格某个单元格的值被编辑后,当焦点移出时,表格会自动调用自己的模型的setValueAt方法,传入改变后的值和行列索引,这个功能也可被利用来做事件响应。 |