淺析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()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM