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

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

 

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

·TableModel接口

1、TableModel为JTable提供

·显示的数据

·表格的维数

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

·应该显示的列标题

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

2、实现TableModel:

TableValues类

 

import javax.swing.table.AbstractTableModel;
/** 
 *     注意:一般使用AbstractTableModel创建TableModel的实现,只有少量数据时使用DefaultTableModel,
 */
public class TableValues extends AbstractTableModel{
         private static final long serialVersionUID = -8430352919270533604L;
         public final static int NAME = 0;
         public final static int GENDER = 1;
         public final static String[] columnNames = {"姓名", "性别"};
         public Object[][] values = {
                            {"Cannel_2020",true},
                            {"Lucy",false},
                            {"韩梅",false},
                            {"李雷",true},
                            {"Jim",true}
         };
         publicint getColumnCount() {
                   return  values[0].length;
         }
         publicint getRowCount() {
                   return values.length;
         }
         public Object getValueAt(int rowIndex, int columnIndex) {
                   return values[rowIndex][columnIndex];
         }


         /**
          * 获取列名
          */
         publicString getColumnName(int column){
                   return columnNames[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 extends JFrame{
       
         private static final long serialVersionUID = -4172876583187222326L;
         protected JTable table;
         public SimpleTableTest(){
                   Container pane = getContentPane();
                   pane.setLayout(newBorderLayout());


                   TableValues tv =  new TableValues();
                   table= new JTable(tv);


                   //设置行高
                   table.setRowHeight(30);
                   //必须把table放入JScrollPane才会有列名出现
                   JScrollPane jsp = 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去通知编辑器已经结束编辑
                           <span style="white-space:pre"> </span>     //在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()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 AbstractTableModel 构建Table 在表格中添加JButton按钮,之前在网上找了2天没有找到好用的程序,最终终于找到一个好用的例子。 不要使,我退你们分。。 sing the Swing JTable class can quickly become a sticky business when you want to customize it to your specific needs. First you must become familiar with how the JTable class is organized. Individual cells are rendered by TableCellRenderer implementations. The table contents are represented by an implementation of the TableModel interface. By default, JTable uses DefaultTableCellRenderer to draw its cells. DefaultTableCellRenderer recognizes a few primitive types, rendering them as strings, and can even display Boolean types as checkboxes. But it defaults to displaying the value returned by toString() for types it does not specifically handle. You have to provide your own TableCellRenderer implementation if you want to display buttons in a JTable. The TableCellRenderer interface contains only one method, getTableCellRendererComponent(...), which returns a java.awt.Component that knows how to draw the contents of a specific cell. Usually, getTableCellRendererComponent() will return the same component for every cell of a column, to avoid the unnecessary use of extra memory. But when the contents of a cell is itself a component, it is all right to return that component as the renderer. Therefore, the first step towards having JButtons display correctly in a JTable is to create a TableCellRenderer implementation that returns the JButton contained in the cell being rendered. In the accompanying code listing, JTableButtonRenderer demonstrates how to do this. Even after creating a custom TableCellRenderer, you're still not done. The TableModel associated with a given JTable does not only keep track of the contents of each cell, but it also keeps track of the class of data stored in each column. DefaultTableModel is designed to work with DefaultTableCellRenderer and will return java.lang.String.class for columns containing data types that it does not specifically handle. The exact method that does this is getColumnClass(int column). Your second step is to create a TableModel implementation that returns JButton.class for cells that contain JButtons. JTableButtonModel shows one way to do this. It just returns the result of getClass() for each piece of cell data. At this point, you're almost done, but not quite. What's the use of putting a JButton in a JTable if you can't press the darn thing? By default, JTable will not forward mouse events to components contained in its cells. If you want to be able to press the buttons you add to JTable, you have to create your own MouseListener that forwards events to the JButton cells. JTableButtonMouseListener demonstrates how you could do this.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值