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

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

·TableModel接口

1、TableModel为JTable提供

·显示的数据

·表格的维数

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

·应该显示的列标题

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

2、实现TableModel:

TableValues类

importjavax.swing.table.AbstractTableModel;
/**  
 *     注意:一般使用AbstractTableModel创建TableModel的实现,只有少量数据时使用DefaultTableModel,
 */
public class TableValues extendsAbstractTableModel{
         privatestatic final long serialVersionUID = -8430352919270533604L;
         publicfinal static int NAME = 0;
         publicfinal static int GENDER = 1;
         publicfinal static String[] columnNames = {"姓名", "性别"};
         publicObject[][] values = {
                            {"Cannel_2020",true},
                            {"Lucy",false},
                            {"韩梅",false},
                            {"李雷",true},
                            {"Jim",true}
         };
         publicint getColumnCount() {
                   returnvalues[0].length;
         }
         publicint getRowCount() {
                   returnvalues.length;
         }
         publicObject getValueAt(int rowIndex, int columnIndex) {
                   returnvalues[rowIndex][columnIndex];
         }
         /**
          * 设置列名
          */
         publicString getColumnName(int column){
                   returncolumnNames[column];
         }
}

SimpleTableTest类

import java.awt.BorderLayout;
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class SimpleTableTest extendsJFrame{
        
         privatestatic final long serialVersionUID = -4172876583187222326L;
         protected JTable table;
         publicSimpleTableTest(){
                   Containerpane = getContentPane();
                   pane.setLayout(newBorderLayout());
                   TableValuestv =  new TableValues();
                   table= new JTable(tv);
                   //设置行高
                   table.setRowHeight(30);
                   //必须把table放入JScrollPane才会有列名出现
                   JScrollPanejsp = new JScrollPane(table);
                   pane.add(jsp,BorderLayout.CENTER);
         }
         publicstatic void main(String[] args) {
                   SimpleTableTeststt = new SimpleTableTest();
                   stt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                   stt.setSize(400,200);
                   stt.setVisible(true);
         }
}

运行结果:


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

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

GenderRenderer类

import java.awt.Component;
import javax.swing.JComboBox;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
 
public class GenderRenderer extendsJComboBox implements TableCellRenderer{
         privatestatic final long serialVersionUID = -8624401777277852691L;
         publicGenderRenderer(){
                   super();
                   addItem("男");
                   addItem("女");
         }
         publicComponent getTableCellRendererComponent(JTable table, Object value,
                            booleanisSelected, boolean hasFocus, int row, int column) {
                   if(isSelected){
                            setForeground(table.getForeground());
                            super.setBackground(table.getBackground());
                   }else{
                            setForeground(table.getForeground());
                            setBackground(table.getBackground());
                   }
                   booleanisMale = ((Boolean)value).booleanValue();
                   setSelectedIndex(isMale? 0 : 1);
                   returnthis;
         }
 
}

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

public SimpleTableTest(){
                   setTitle("FromCannel_2020's blog(CSDN)");
                   setLayout(newBorderLayout());
                   TableValuestv =  new TableValues();
                   table= new JTable(tv);
                   //设置行宽
                   table.setRowHeight(30);
                  
                   TableColumnModeltcm= table.getColumnModel();
                   TableColumntc = tcm.getColumn(TableValues.GENDER);
                   //设置“性别”列的单元格渲染器(renderer)
                   tc.setCellRenderer(newGenderRenderer());
                  
                   //必须把table放入JScrollPane才会有列名出现
                   JScrollPanejsp = new JScrollPane(table);
                   add(jsp,BorderLayout.CENTER);
         }

运行结果:


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

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

    /**
     * 设置单元格可以编辑
     */
    public booleanisCellEditable(int row, int column){
       returntrue;
    }

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


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

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

1、

import java.awt.Component;
import java.util.EventObject;
import javax.swing.JComboBox;
import javax.swing.JTable;
importjavax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.EventListenerList;
import javax.swing.table.TableCellEditor;
 
public class GenderEditor extends JComboBoximplements TableCellEditor{
        
         privatestatic final long serialVersionUID = 5860619160549087886L;
         //EventListenerList:保存EventListener 列表的类。
         privateEventListenerList listenerList = new EventListenerList();
         //ChangeEvent用于通知感兴趣的参与者事件源中的状态已发生更改。
         privateChangeEvent changeEvent = new ChangeEvent(this);
         publicGenderEditor(){
                   super();
                   addItem("男");
                   addItem("女");
                   //请求终止编辑操作可以包含单元格的JTable收到,也可以从编辑器组件本身(如这里的JComboBox)获得
                   /*addActionListener(newActionListener(){
                            publicvoid actionPerformed(ActionEvent e) {
                                     System.out.println("ActionListener");
                                     //如同stopCellEditing,都是调用fireEditingStopped()方法
                                     fireEditingStopped();
                            }
                           
                   });*/
         }
         publicvoid addCellEditorListener(CellEditorListener l) {
                   listenerList.add(CellEditorListener.class,l);
         }
         publicvoid removeCellEditorListener(CellEditorListener l) {
                   listenerList.remove(CellEditorListener.class,l);
         }
         privatevoid fireEditingStopped(){
                   CellEditorListenerlistener;
                   Object[]listeners = listenerList.getListenerList();
                   for(inti = 0; i < listeners.length; i++){
                            if(listeners[i]== CellEditorListener.class){
                                     //之所以是i+1,是因为一个为CellEditorListener.class(Class对象),
                                     //接着的是一个CellEditorListener的实例
                                     listener= (CellEditorListener)listeners[i+1];
                                     //让changeEvent去通知编辑器已经结束编辑
                           	     //在editingStopped方法中,JTable调用getCellEditorValue()取回单元格的值,
                                     //并且把这个值传递给TableValues(TableModel)的setValueAt()
                                     listener.editingStopped(changeEvent);
                            }
                   }
         }
         publicvoid cancelCellEditing() {         
         }
         /**
          * 编辑其中一个单元格,再点击另一个单元格时,调用。-------------!!!!!
          */
         publicboolean stopCellEditing() {
                   //可以注释掉下面的fireEditingStopped();,然后在GenderEditor的构造函数中把
                   //addActionListener()的注释去掉(这时请求终止编辑操作从JComboBox获得),
                   System.out.println("编辑其中一个单元格,再点击另一个单元格时,调用。");
                   fireEditingStopped();//请求终止编辑操作从JTable获得
                   returntrue;
         }
         /**
          * 为一个单元格初始化编辑时,getTableCellEditorComponent被调用
          */
         publicComponent getTableCellEditorComponent(JTable table, Object value,
                            booleanisSelected, int row, int column) {
                   booleanisMale = ((Boolean)value).booleanValue();
                   setSelectedIndex(isMale? 0 : 1);
                   returnthis;
         }
         /**
          * 询问编辑器它是否可以使用 anEvent 开始进行编辑。
          */
         publicboolean isCellEditable(EventObject anEvent) {
                   returntrue;
         }
         /**
          * 如果应该选择正编辑的单元格,则返回true,否则返回 false。
          */
         publicboolean shouldSelectCell(EventObject anEvent) {
                   returntrue;
         }
 
         /**
          * 返回值传递给TableValue(TableModel)中的setValueAt()方法
          */
         publicObject getCellEditorValue() {
                   returnnew Boolean(getSelectedIndex() == 0 ? true : false);
         }
}

2、SimpleTableTest类的构造函数中

tc.setCellRenderer(new GenderRenderer());

后面加入:

//设置“性别”列的单元格编辑器(editor)
tc.setCellEditor(new GenderEditor());

运行结果:


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

       /**
          * 单元格被编辑完后,调用此方法更新值
          */
         publicvoid setValueAt(Object value, int row, int column){
                   values[row][column]= value;
         }

4、GenderEditor类的工作流程:

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

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

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

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值