浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值

如同其它的Swing组件,JTable使用MVC(模型、试图、控制器)设计方式,将可视化组件(JTable实例)从其数据(TableModel实现)中分离出来。

·TableModel接口

1、TableModel为JTable提供

·显示的数据

·表格的维数

·表格中每一列所包含的数据类型

·应该显示的列标题

·是否允许编辑指定单元格的值

2、实现TableModel:

TableValues类

[java]  view plain copy
  1. importjavax.swing.table.AbstractTableModel;  
  2. /**   
  3.  *     注意:一般使用AbstractTableModel创建TableModel的实现,只有少量数据时使用DefaultTableModel, 
  4.  */  
  5. public class TableValues extendsAbstractTableModel{  
  6.          privatestatic final long serialVersionUID = -8430352919270533604L;  
  7.          publicfinal static int NAME = 0;  
  8.          publicfinal static int GENDER = 1;  
  9.          publicfinal static String[] columnNames = {"姓名""性别"};  
  10.          publicObject[][] values = {  
  11.                             {"Cannel_2020",true},  
  12.                             {"Lucy",false},  
  13.                             {"韩梅",false},  
  14.                             {"李雷",true},  
  15.                             {"Jim",true}  
  16.          };  
  17.          publicint getColumnCount() {  
  18.                    returnvalues[0].length;  
  19.          }  
  20.          publicint getRowCount() {  
  21.                    returnvalues.length;  
  22.          }  
  23.          publicObject getValueAt(int rowIndex, int columnIndex) {  
  24.                    returnvalues[rowIndex][columnIndex];  
  25.          }  
  26.          /** 
  27.           * 设置列名 
  28.           */  
  29.          publicString getColumnName(int column){  
  30.                    returncolumnNames[column];  
  31.          }  
  32. }  

SimpleTableTest类

[java]  view plain copy
  1. import java.awt.BorderLayout;  
  2. import java.awt.Container;  
  3. import javax.swing.JFrame;  
  4. import javax.swing.JScrollPane;  
  5. import javax.swing.JTable;  
  6. import javax.swing.table.TableColumn;  
  7. import javax.swing.table.TableColumnModel;  
  8. public class SimpleTableTest extendsJFrame{  
  9.           
  10.          privatestatic final long serialVersionUID = -4172876583187222326L;  
  11.          protected JTable table;  
  12.          publicSimpleTableTest(){  
  13.                    Containerpane = getContentPane();  
  14.                    pane.setLayout(newBorderLayout());  
  15.                    TableValuestv =  new TableValues();  
  16.                    table= new JTable(tv);  
  17.                    //设置行高  
  18.                    table.setRowHeight(30);  
  19.                    //必须把table放入JScrollPane才会有列名出现  
  20.                    JScrollPanejsp = new JScrollPane(table);  
  21.                    pane.add(jsp,BorderLayout.CENTER);  
  22.          }  
  23.          publicstatic void main(String[] args) {  
  24.                    SimpleTableTeststt = new SimpleTableTest();  
  25.                    stt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  26.                    stt.setSize(400,200);  
  27.                    stt.setVisible(true);  
  28.          }  
  29. }  

运行结果:

浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值_第1张图片

·实现TableCellRenderer(单元格渲染器)接口

1、使表格“性别”一列的单元格出现JComboBox组件

GenderRenderer类

[java]  view plain copy
  1. import java.awt.Component;  
  2. import javax.swing.JComboBox;  
  3. import javax.swing.JTable;  
  4. import javax.swing.table.TableCellRenderer;  
  5.    
  6. public class GenderRenderer extendsJComboBox implements TableCellRenderer{  
  7.          privatestatic final long serialVersionUID = -8624401777277852691L;  
  8.          publicGenderRenderer(){  
  9.                    super();  
  10.                    addItem("男");  
  11.                    addItem("女");  
  12.          }  
  13.          publicComponent getTableCellRendererComponent(JTable table, Object value,  
  14.                             booleanisSelected, boolean hasFocus, int row, int column) {  
  15.                    if(isSelected){  
  16.                             setForeground(table.getForeground());  
  17.                             super.setBackground(table.getBackground());  
  18.                    }else{  
  19.                             setForeground(table.getForeground());  
  20.                             setBackground(table.getBackground());  
  21.                    }  
  22.                    booleanisMale = ((Boolean)value).booleanValue();  
  23.                    setSelectedIndex(isMale? 0 : 1);  
  24.                    returnthis;  
  25.          }  
  26.    
  27. }  

2、SimpleTableTest类的构造函数改变如下:

[java]  view plain copy
  1. public SimpleTableTest(){  
  2.                    setTitle("FromCannel_2020's blog(CSDN)");  
  3.                    setLayout(newBorderLayout());  
  4.                    TableValuestv =  new TableValues();  
  5.                    table= new JTable(tv);  
  6.                    //设置行宽  
  7.                    table.setRowHeight(30);  
  8.                     
  9.                    TableColumnModeltcm= table.getColumnModel();  
  10.                    TableColumntc = tcm.getColumn(TableValues.GENDER);  
  11.                    //设置“性别”列的单元格渲染器(renderer)  
  12.                    tc.setCellRenderer(newGenderRenderer());  
  13.                     
  14.                    //必须把table放入JScrollPane才会有列名出现  
  15.                    JScrollPanejsp = new JScrollPane(table);  
  16.                    add(jsp,BorderLayout.CENTER);  
  17.          }  

运行结果:

浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值_第2张图片

3、注意:渲染器实际上并没有像可视化组件添加到Container中那样添加到JTable实例中,即表格中不含有JComboBox实例。此时,是将唯一的JComboBox实例绘制(通过向paint()方法传递Graphics对象)到“性别”一列的每一个单元格所占用的区域中。

4、在TableValues添加如下代码(覆盖AbstractTableModel中的方法),使得JTable实例中单元格可以编辑:

[java]  view plain copy
  1. /** 
  2.  * 设置单元格可以编辑 
  3.  */  
  4. public booleanisCellEditable(int row, int column){  
  5.    returntrue;  
  6. }  

然而此时对“性别”一列的单元格进行编辑,会出现如下情况:

浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值_第3张图片

这就得使用到单元格编辑器了。

·实现TableCellEditor(单元格编辑器)接口

1、

[java]  view plain copy
  1. import java.awt.Component;  
  2. import java.util.EventObject;  
  3. import javax.swing.JComboBox;  
  4. import javax.swing.JTable;  
  5. importjavax.swing.event.CellEditorListener;  
  6. import javax.swing.event.ChangeEvent;  
  7. import javax.swing.event.EventListenerList;  
  8. import javax.swing.table.TableCellEditor;  
  9.    
  10. public class GenderEditor extends JComboBoximplements TableCellEditor{  
  11.           
  12.          privatestatic final long serialVersionUID = 5860619160549087886L;  
  13.          //EventListenerList:保存EventListener 列表的类。  
  14.          privateEventListenerList listenerList = new EventListenerList();  
  15.          //ChangeEvent用于通知感兴趣的参与者事件源中的状态已发生更改。  
  16.          privateChangeEvent changeEvent = new ChangeEvent(this);  
  17.          publicGenderEditor(){  
  18.                    super();  
  19.                    addItem("男");  
  20.                    addItem("女");  
  21.                    //请求终止编辑操作可以包含单元格的JTable收到,也可以从编辑器组件本身(如这里的JComboBox)获得  
  22.                    /*addActionListener(newActionListener(){ 
  23.                             publicvoid actionPerformed(ActionEvent e) { 
  24.                                      System.out.println("ActionListener"); 
  25.                                      //如同stopCellEditing,都是调用fireEditingStopped()方法 
  26.                                      fireEditingStopped(); 
  27.                             } 
  28.                             
  29.                    });*/  
  30.          }  
  31.          publicvoid addCellEditorListener(CellEditorListener l) {  
  32.                    listenerList.add(CellEditorListener.class,l);  
  33.          }  
  34.          publicvoid removeCellEditorListener(CellEditorListener l) {  
  35.                    listenerList.remove(CellEditorListener.class,l);  
  36.          }  
  37.          privatevoid fireEditingStopped(){  
  38.                    CellEditorListenerlistener;  
  39.                    Object[]listeners = listenerList.getListenerList();  
  40.                    for(inti = 0; i < listeners.length; i++){  
  41.                             if(listeners[i]== CellEditorListener.class){  
  42.                                      //之所以是i+1,是因为一个为CellEditorListener.class(Class对象),  
  43.                                      //接着的是一个CellEditorListener的实例  
  44.                                      listener= (CellEditorListener)listeners[i+1];  
  45.                                      //让changeEvent去通知编辑器已经结束编辑  
  46.                            <span style="white-space:pre">   </span>     //在editingStopped方法中,JTable调用getCellEditorValue()取回单元格的值,  
  47.                                      //并且把这个值传递给TableValues(TableModel)的setValueAt()  
  48.                                      listener.editingStopped(changeEvent);  
  49.                             }  
  50.                    }  
  51.          }  
  52.          publicvoid cancelCellEditing() {           
  53.          }  
  54.          /** 
  55.           * 编辑其中一个单元格,再点击另一个单元格时,调用。-------------!!!!! 
  56.           */  
  57.          publicboolean stopCellEditing() {  
  58.                    //可以注释掉下面的fireEditingStopped();,然后在GenderEditor的构造函数中把  
  59.                    //addActionListener()的注释去掉(这时请求终止编辑操作从JComboBox获得),  
  60.                    System.out.println("编辑其中一个单元格,再点击另一个单元格时,调用。");  
  61.                    fireEditingStopped();//请求终止编辑操作从JTable获得  
  62.                    returntrue;  
  63.          }  
  64.          /** 
  65.           * 为一个单元格初始化编辑时,getTableCellEditorComponent被调用 
  66.           */  
  67.          publicComponent getTableCellEditorComponent(JTable table, Object value,  
  68.                             booleanisSelected, int row, int column) {  
  69.                    booleanisMale = ((Boolean)value).booleanValue();  
  70.                    setSelectedIndex(isMale? 0 : 1);  
  71.                    returnthis;  
  72.          }  
  73.          /** 
  74.           * 询问编辑器它是否可以使用 anEvent 开始进行编辑。 
  75.           */  
  76.          publicboolean isCellEditable(EventObject anEvent) {  
  77.                    returntrue;  
  78.          }  
  79.          /** 
  80.           * 如果应该选择正编辑的单元格,则返回true,否则返回 false。 
  81.           */  
  82.          publicboolean shouldSelectCell(EventObject anEvent) {  
  83.                    returntrue;  
  84.          }  
  85.    
  86.          /** 
  87.           * 返回值传递给TableValue(TableModel)中的setValueAt()方法 
  88.           */  
  89.          publicObject getCellEditorValue() {  
  90.                    returnnew Boolean(getSelectedIndex() == 0 ? true : false);  
  91.          }  
  92. }  

2、SimpleTableTest类的构造函数中

[java]  view plain copy
  1. tc.setCellRenderer(new GenderRenderer());  

后面加入:

[java]  view plain copy
  1. //设置“性别”列的单元格编辑器(editor)  
  2. tc.setCellEditor(new GenderEditor());  

运行结果:

浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值_第4张图片

3、还有一点别忘了再在TableValues加入如下代码(原因:看第4的最后一点

[java]  view plain copy
  1. /** 
  2.    * 单元格被编辑完后,调用此方法更新值 
  3.    */  
  4.   publicvoid setValueAt(Object value, int row, int column){  
  5.             values[row][column]= value;  
  6.   }  

4、GenderEditor类的工作流程:

1)、调用TableCellEditor接口中的getTableCellEditorComponent()方法初始化编辑

2)、编辑当前的单元格,再点击另一个单元格时,调用CellEditor中的stopCellEditing(),通过fireEditingStopped()调用到editingStopped()。

3)、在editingStopped方法中,JTable调用getCellEditorValue()取回单元格的值,并且把这个值传递给TableValues(TableModel)的setValueAt()


你可能感兴趣的:(浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值)