表格(Table)的使用與介紹
8-1:使用JTable組件: 類層次結構圖: java.lang.Object --java.awt.Component --java.awt.Container --javax.swing.JComponent --javax.swing.JTabel 在使用JTable以前,我們先看一下它的構造函數有哪些, 以及應該如何使用:
JTabel構造函數: JTable():建立一個新的JTables,并使用系統默認的Model. JTable(int numRows,int numColumns):建立一個具有numRows行,numColumns列的空表格,使用的是DefaultTableModel. JTable(Object[][] rowData,Object[][] columnNames):建立一個顯示二維數組數據的表格,且可以顯示列的名稱。 JTable(TableModel dm):建立一個JTable,有默認的字段模式以及選擇模式,并設置數據模式。 JTable(TableModel dm,TableColumnModel cm):建立一個JTable,設置數據模式與字段模式,并有默認的選擇模式。 JTable(TableModel dm,TableColumnModel cm,ListSelectionModel sm):建立一個JTable,設置數據模式、字段模式、與選擇模式。 JTable(Vector rowData,Vector columnNames):建立一個以Vector為輸入來源的數據表格,可顯示行的名稱。
我們先以Array構造方式,說明如何利用JTable來建立一個簡單的表格:
1 import javax.swing.*; 2 import java.awt.*; 3 import java.awt.event.*; 4 import java.util.*; 5 public class SimpleTable{ 6 public SimpleTable(){ 7 JFrame f=new JFrame(); 8 Object[][] playerInfo={ 9 ?? {"阿呆",new Integer(66),new Integer(32),new Integer(98),new Boolean(false)}, 10 {"阿呆",new Integer(82),new Integer(69),new Integer(128),new Boolean(true)}, 11 };?? 12 String[] Names={"姓名","語文","數學","總分","及格"}; 13 JTable table=new JTable(playerInfo,Names); 14 table.setPreferredScrollableViewportSize(new Dimension(550,30)); 15 JScrollPane scrollPane=new JScrollPane(table); 16 f.getContentPane().add(scrollPane,BorderLayout.CENTER); 17 f.setTitle("Simple Table"); 18 f.pack(); 19 f.show(); 20 f.addWindowListener(new WindowAdapter() { 21 public void windowClosing(WindowEvent e) { 22 System.exit(0); 23 } 24 }); 24 }?? 25 public static void main(String[] args){ 26 ?? SimpleTable b=new SimpleTable(); 27 } 28 }
表格由兩部份組成:分別是行標題(Column Header)與行對象(Column Object).利用JTable所提供的getTableHeader()方法取得 行標題。在這個例子中,我們將JTable放在JScrollPane中,這種做法可以將Column Header與Colmn Object完整的顯示出來,因為 JScrollPane會自動取得Column Header.但如果文壇讀者將上面第15行去掉并修改第16行: f.getContentPane().add(table,BorderLayout.CENTER); 則運行結果你會發現Column Header不見了。 如果你不想用JScrollPane,要解決這個問題,你必須將程序修改如下:
JTable table=new JTable(p,n); table.setPreferredScrollableViewportSize(new Dimension(550,30)); f.getContentPane().add(table.getTableHeader(),BorderLayout.NORTH); f.getContentPane().add(table,BorderLayout.CENTER);
運行結果就會跟之前一樣有行標題了. 上面的運行結果就會跟發現,每個字段的寬度都是一樣的,除非你自行拉曳某個列寬。若我們想一開始就設置列寬的值,可以利 用TableColumn類所提供的setPreferredWidth()方法來設置,并可利用JTable類所提供的setAutoResizeMode()方法來設置調整某個 列寬時其他列寬的變化情況,我們看下面這個例子:
import javax.swing.*; import javax.swing.table.*; import java.awt.*; import java.awt.event.*; import java.util.*; public class SimpleTable2{ public SimpleTable2(){ JFrame f=new JFrame(); Object[][] p={ ?? {"阿呆",new Integer(66),new Integer(32),new Integer(98),new Boolean(false),new Boolean(false)}, {"阿呆",new Integer(82),new Integer(69),new Integer(128),new Boolean(true),new Boolean(false)}, };?? String[] n={"姓名","語文","數學","總分","及格","作弊"}; TableColumn column=null; JTable table=new JTable(p,n); table.setPreferredScrollableViewportSize(new Dimension(550,30)); table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); for (int i=0;i<6;i++){ //利用JTable中的getColumnModel()方法取得TableColumnModel對象;再利用TableColumnModel界面所定義的getColumn()方法取 //TableColumn對象,利用此對象的setPreferredWidth()方法就可以控制字段的寬度. ?? column=table.getColumnModel().getColumn(i); ?? if ((i%2)==0) ?? column.setPreferredWidth(150); ?? else ?? column.setPreferredWidth(50); } JScrollPane scrollPane=new JScrollPane(table); f.getContentPane().add(scrollPane,BorderLayout.CENTER); f.setTitle("Simple Table"); f.pack(); f.show(); f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); ?? } public static void main(String[] args){ ?? new SimpleTable2(); } }
列可調整的5個參數: AUTO_RESIZE_SUBSEQUENT_COLUMENS:當調整某一列寬時,此字段之后的所有字段列寬都會跟著一起變動。此為系統默認值。 AUTO_RESIZE_ALL_COLUMNS:當調整某一列寬時,此表格上所有字段的列寬都會跟著一起變動。 AUTO_RESIZE_OFF:當調整某一列寬時,此表格上所有字段列寬都不會跟著改變。 AUTO_RESIZE_NEXT_COLUMN:當調整某一列寬時,此字段的下一個字段的列寬會跟著改變,其余均不會變。 AUTO_RESIZE_LAST_COLUMN:當調整某一列寬時,最后一個字段的列寬會跟著改變,其余均不會改變。
由以上范例可知,利用Swing來構造一個表格其實很簡單的,只要你利用Vector或Array來作為我們表格的數據輸入,將Vector或Array的 內容填入JTable中,一個基本的表格就產生了。不過,雖然利用JTable(Object[][] rowData,Object[][] columnNames)以及 JTable(Vector rowData,Vector columnNames)構造函數來構造構造JTable很方便,但卻有些缺點。例如上例中,我們表格中的每個字段 (cell)一開始都是默認為可修改的,用戶因此可能修改到我們的數據;其次,表格中每個單元(cell)中的數據類型將會被視為同一種。在我 們的例子中,數據類型皆被顯示為String的類型,因此,原來的數據類型聲明為Boolean的數據會以String的形式出現而不是以檢查框( Check Box)出現。 除此之外,如果我們所要顯示的數據是不固定的,或是隨情況而變,例如同樣是一份成績單,老師與學生所看到的表格就不會一樣,顯 示的外觀或操作模式也許也不相同。為了因應這些種種復雜情況,上面簡單的構造方式已不宜使用,Swing提供各種Model(如: TableModel、TableColumnModel與ListSelectionModel)來解決上述的不便,以增加我們設計表格的彈性。我們下面就先對TableModel來 做介紹:
8-2:TableModel TableModel類本身是一個interface,在這個interface里面定義了若干的方法:包括了存取表格字段(cell)的內容、計算表格的列數等等 的基本存取操作,讓設計者可以簡單地利用TableModel來實作他所想要的表格。TableModel界面是放在javax.swing.table package中,這 個package定義了許多JTable會用到的各種Model,讀者可利用java api文件找到這個package,并由此package找到各類或界面所定義的方法 。 TableModel方法: void addTableModelListener(TableModelListener l):使表格具有處理TableModelEvent的能力。當表格的Table Model有所 變化時,會發出TableModel Event事件信息. Class getColumnClass(int columnIndex):返回字段數據類型的類名稱. int getColumnCount():返回字段(行)數量. String getColumnName(int columnIndex):返回字段名稱. int getRowCount():返回數據列數量. Object getValueAt(int rowIndex,int columnIndex):返回數據某個cell中的值. boolean isCellEditable(int rowIndex,int columnIndex):返回cell是否可編輯,true的話為可編輯. void removeTableModelListener(TableModelListener l):從TableModelListener中移除一個listener. void setValueAt(Object aValue,int rowIndex,int columnIndex):設置某個cell(rowIndex,columnIndex)的值;
由于TableModel本身是一個Interface,因此若要直接實現此界面來建立表格并不是件輕松的事.幸好java提供了兩個類分別實現了這個 界面,一個是AbstractTableModel抽象類,一個是DefaultTableModel實體類.前者實現了大部份的TableModel方法,讓用戶可以很有彈性地構 造自己的表格模式;后者繼承前者類,是java默認的表格模式.這三者的關系如下所示: TableModel---implements--->AbstractTableModel-----extends--->DefaultTableModel
8-3:AbstractTableModel:
java提供的AbstractTableModel是一個抽象類,這個類幫我們實現大部份的TableModel方法,除了getRowCount(),getColumnCount(), getValueAt()這三個方法外.因此我們的主要任務就是去實現這三個方法.利用這個抽象類就可以設計出不同格式的表格.我們來看看它所 提供的方法: AbstractTableModel方法: void addTableModelListener(TableModelListener l):使表格具有處理TableModelEvent的能力.當表格的Table Model有所變化時,會發 出TableModelEvent事件信息. int findColumn(String columnName):尋找在行名稱中是否含有columnName這個項目.若有,則返回其所在行的位置;反之則返回-1表示 未找到. void fireTableCellUpdated(int row, int column):通知所有的Listener在這個表格中的(row,column)字段的內容已經改變了. void fireTableChanged(TableModelEvent e):將所收的事件通知傳送給所有在這個table model中注冊過的TableModelListeners. void fireTableDataChanged():通知所有的listener在這個表格中列的內容已經改變了.列的數目可能已經改變了,因此JTable可能需要 重新顯示此表格的結構. void fireTableRowsDeleted(int firstRow, int lastRow):通知所有的listener在這個表格中第firstrow行至lastrow列已經被刪除了. void fireTableRowsUpdated(int firstRow, int lastRow) :通知所有的listener在這個表格中第firstrow行至lastrow列已經被修改了. void fireTableRowsInserted(int firstRow, int lastRow):通知所有的listener在這個表格中第firstrow行至lastrow列已經被加入了 .
void fireTableStructureChanged():通知所有的listener在這個表格的結構已經改變了.行的數目,名稱以及數據類型都可能已經改變了 . Class getColumnClass(int columnIndex):返回字段數據類型的類名稱. String getColumnName(int column):若沒有設置列標題則返回默認值,依次為A,B,C,...Z,AA,AB,..;若無此column,則返回一個空的String . Public EventListener[] getListeners(Class listenerType):返回所有在這個table model所建立的listener中符合listenerType的 listener,并以數組形式返回. boolean??isCellEditable(int rowIndex, int columnIndex) :返回所有在這個table model所建立的listener中符合listenerType形式的 listener,并以數組形式返回. void??removeTableModelListener(TableModelListener l):從TableModelListener中移除一個listener.
void??setValueAt(Object aValue, int rowIndex, int columnIndex) :設置某個cell(rowIndex,columnIndex)的值. 若你仔細比較TableModel所定義的方法與上述AbstractTableModel所提供的方法,你可以發現,AbstractTableModel抽象類并沒有實現 getRowCount(),getColumnCount(),getValueAt()這三個方法,這也就是為什么我們要去實現這三個方法的原因.下面我們來看如何使用 AbstractTableModel來實作出自己想要的表格模式.
范例:TableModel1.java
import javax.swing.table.AbstractTableModel; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class TableModel1{ public TableModel1() { ??JFrame f = new JFrame(); ??MyTable mt=new MyTable(); ??JTable t=new JTable(mt); ??t.setPreferredScrollableViewportSize(new Dimension(550, 30)); JScrollPane s = new JScrollPane(t); f.getContentPane().add(s, BorderLayout.CENTER); ?? f.setTitle("JTable1"); f.pack(); f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public static void main(String args[]) {
new TableModel1(); } } class MyTable extends AbstractTableModel{ Object[][] p = { {"阿呆", new Integer(66), new Integer(32), new Integer(98), new Boolean(false),new Boolean(false)}, {"阿瓜", new Integer(85), new Integer(69), new Integer(154), new Boolean(true),new Boolean(false)}, }; String[] n = {"姓名", "語文", "數學", "總分", "及格", ???? "作弊"}; public int getColumnCount() { return n.length; } public int getRowCount() { return p.length; } public String getColumnName(int col) { return n[col]; } public Object getValueAt(int row, int col) { return p[row][col]; } ??public Class getColumnClass(int c) { ?? return getValueAt(0, c).getClass(); ??} }
上例中表格內的數據類型不論是String,int或是Boolean類型,都均以string的類型顯示.例如在及格的字段中,原本的數據是以Boolean 類型來表示,但顯示在JTable上時便轉換成字符串形式,若想要使表格能顯示出不同的數據類型,我們要在MyTable中Override寫getColumnCl ass()方法,這個方法可以讓我們分辨出表格中每一行的數據類型,并將此類型作適當的顯示: ??public Class getColumnClass(int c) { ?? return getValueAt(0, c).getClass(); ??} 這樣"作弊"會以Check Box顯示,數據類型一律靠右顯示,String類型一律靠左顯示. TableModel2.java
import javax.swing.table.AbstractTableModel; import javax.swing.*; import java.awt.*; import java.awt.event.*;
public class TableModel2 implements ActionListener{
JTable t = null;
public TableModel2() {
??JFrame f = new JFrame("DataModel"); ??JButton b1 = new JButton("數學老師"); ??b1.addActionListener(this); ??JButton b2 = new JButton("學生阿呆"); ??b2.addActionListener(this); ??JPanel panel = new JPanel(); ??panel.add(b1); ??panel.add(b2); ?? ??t=new JTable(new MyTable(1)); ??t.setPreferredScrollableViewportSize(new Dimension(550, 30)); JScrollPane s = new JScrollPane(t);
f.getContentPane().add(panel, BorderLayout.NORTH); f.getContentPane().add(s, BorderLayout.CENTER); f.pack(); f.setVisible(true);
f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); }
public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("學生阿呆")) t.setModel(new MyTable(1)); if (e.getActionCommand().equals("數學老師")) t.setModel(new MyTable(2)); t.revalidate(); }
public static void main(String args[]) {
new TableModel2(); } }
class MyTable extends AbstractTableModel{
Object[][] p1 = { {"阿呆", "1234",new Integer(66), new Integer(50), new Integer(116), new Boolean(false),new Boolean(false)}};
String[] n1 = {"姓名","學號","語文","數學","總分","及格","作弊"};
Object[][] p2 = { {"阿呆", "1234",new Integer(50), new Boolean(false),new Boolean(false),"01234"}, {"阿瓜", "1235",new Integer(75), new Boolean(true),new Boolean(false),"05678"}};
String[] n2 = {"姓名","學號","數學","及格","作弊","電話"};
int model = 1;
public MyTable(int i){ model = i; }
public int getColumnCount() { if(model ==1) return n1.length; else return n2.length; }
public int getRowCount() { if(model ==1) return p1.length; else return p2.length; }
public String getColumnName(int col) { if(model ==1) return n1[col]; else return n2[col]; }
public Object getValueAt(int row, int col) { if(model == 1) return p1[row][col]; else return p2[row][col]; }
??public Class getColumnClass(int c) { ?? return getValueAt(0, c).getClass(); ??} }
8-4:TableColumnModel: TableColumnModel本身是一個Interface,里面定義了許多與表格的"列(行)"有關的方法,例如增加列,刪除列,設置與取得"列"的相關信 息.通常我們不會直接實現TableColumnModel界面,而是會利用JTable的getColumnModel()方法取得TableColumnModel對象,再利用此對象對 字段做設置.舉例來說,如果我們想設計的表格是包括有下拉式列表的Combo Box,我們就能利用TableColumnModel來達到這樣的效果. 我們先看看下面的例子:
import javax.swing.table.AbstractTableModel; import javax.swing.*; import java.awt.*; import java.awt.event.*;
public class ColumnModelTest{
public ColumnModelTest() {
??JFrame f = new JFrame(); /*由于我們的MyTable類繼承了AbstractTableModel并且實作了getColmunCount(),getRowCount(),getValueAt()方法.因此我們可以通 *過MyTable來產生TableModel的實體. */ ??MyTable mt=new MyTable(); ??JTable t=new JTable(mt);//我們利用MyTable來建立JTable. ??JComboBox c = new JComboBox();//建立一個JComboBox的對象. ??c.addItem("Taipei");//我們在新建立的JComboBox對象里新增三個項目. ??c.addItem("ChiaYi"); ??c.addItem("HsinChu"); /*我們利用JTable所提供的getTableColumnModel()方法取得TableColumnModel對象,再由TableColumnModel類所提供的getColumn()方 *法取得TableColumn對象,TableColumn類可針對表格中的每一行做具體的設置,例如設置字段的寬度,某行的標頭,設置輸入較復雜的 *數據類型等等.在這里,我們利用TableColumn類所提供的setCellEditor()方法,將JComboBox作為第二行的默認編輯組件. */ ??t.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(c)); ??t.setPreferredScrollableViewportSize(new Dimension(550, 30)); JScrollPane s = new JScrollPane(t);
f.getContentPane().add(s, BorderLayout.CENTER); ?? f.setTitle("ColumnModelTest"); f.pack(); f.setVisible(true);
f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); }
public static void main(String args[]) {
new ColumnModelTest(); }
}
class MyTable extends AbstractTableModel{
Object[][] p = { {"阿呆", "Taipei",new Integer(66), new Integer(32), new Integer(98), new Boolean(false),new Boolean(false)}, {"阿瓜", "ChiaYi",new Integer(85), new Integer(69), new Integer(154), new Boolean(true),new Boolean(false)}, };
String[] n = {"姓名", ?? "居住地", "語文", "數學", "總分", "及格",?????? "作弊"};
public int getColumnCount() { return n.length; }
public int getRowCount() { return p.length; }
public String getColumnName(int col) { return n[col]; }
public Object getValueAt(int row, int col) { return p[row][col]; } ?? public Class getColumnClass(int c) { ??return getValueAt(0, c).getClass(); ??} ?? /*public boolean isCellEditable(int rowIndex, int columnIndex) { ???? return true;?? ??} ?? public void setValueAt(Object value, int row, int col) { ??p[row][col] = value; ???? fireTableCellUpdated(row, col); ??}*/ }
讀者運行此程序可以發現,利用繼承AbstractTableModel抽象類所產生的JTable的內容是不能被修改的.那如果想要讓用戶可以修改表格 中的某一個字段,例如勾選Check Box或是直接修改某個字段的數字,該怎么做呢?很簡單,只要我們在范例中的MyTable類中覆寫AbstractTab leModel抽象類中的isCellEditable()方法即可.下面即是isCellEditable()的實作: public boolean isCellEditable(int rowIndex,int columnIndex){ return true; } 在isCellEditable()中,我們只有一行簡單的程序代碼:return true,意思是將我們表格內的每個cell都變成可修改.但僅僅修改這個程 序代碼還不行,你可以發現雖然表格現在變成了可以修改了,但更改完之后按下[Enter]鍵,內容馬上恢復成原有的值!解決的方法是覆寫 AbstractTableModel抽象類中的setValueAt()方法,這個方法主要是讓我們將改過的值存入表格中,如下所示:
public void setValueAt(Object value,int row,int col){ p[row][col]=value; fireTableCellUpdated(row,col); }
其中value為我們所更改的值,我們將value存入p[row][col]中,并且調用firTableCellUpdated()函數來告訴我們的系統表格已經做了更 改了,關于這一部份,我們后面會再對事件處理作詳細地介紹,在此范例中有沒有加入fireTableCellUpdated()方法對運行結果不會造成影響 .
8-5:SelectionModel 表格的選擇模式是依據我們前面所講的ListSelectionModel而來,因此它的操作模式與事件處理跟JList沒什么分別!我們稍微復習一 下ListSelectionModel這個Interface,它包含了3個常數值,如下: static int SINGLE_SELECTION static int SINGLE_INTERVAL_SELECTION static int MULTIPLE_INTERVAL_SELECTION 分別可讓用戶作單一選擇,連續區間選擇與多重選擇.當用戶作后面兩個模式的操作時,應配合[Shift]鍵或[Ctrl]鍵. 要使用ListSelectionModel可利用JTable的getSelectionModel()方法取得ListSelectionModel對象,再利用ListSelectionModel界面所 定義的setSelectionModel()來設置選擇模式. 如同JList一般,當用戶對表格作數據域位的選取時會產生ListSelectionEvent事件,要處理這個事件就必須實現ListSelectionListener 這個界面,此界面定義了一個方法,那就是valueChanged(). 我們來看下面的例子,用戶可在按鈕上選擇哪種選擇模式,當用戶選取表格數據時,程序會將用戶選取的數據顯示在表格下面的JLabel中. SelectionModelDemo.java
import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*;
public class SelectionModelDemo implements ActionListener,ListSelectionListener{ JTable table=null; ListSelectionModel selectionMode=null; JLabel label=null;//顯示用戶選取表格之用 public SelectionModelDemo(){ ?? JFrame f=new JFrame(); ?? String[] name={"字段1","字段2","字段3","字段4","字段5"}; ?? String[][] data=new String[5][5]; ?? int value=1; ?? for(int i=0;i<data.length;i++){ ?? ?? for (int j=0;j<data[i].length;j++){ ?? ?? ?? data[i][j]=String.valueOf(value++); ?? ?? } ?? } ?? table=new JTable(data,name); ?? table.setPreferredScrollableViewportSize(new Dimension(400,80)); ?? table.setCellSelectionEnabled(true);//使得表格的選取是以cell為單位,而不是以列為單位.若你沒有寫此行,則在選取表格數 //據時以整列為單位. ?? selectionMode=table.getSelectionModel();//取得table的ListSelectionModel. ?? selectionMode.addListSelectionListener(this); ?? JScrollPane s=new JScrollPane(table); ?? JPanel panel=new JPanel(); ?? JButton b=new JButton("單一選擇"); ?? panel.add(b); ?? b.addActionListener(this); ?? b=new JButton("連續區間選擇"); ?? panel.add(b); ?? b.addActionListener(this); ?? b=new JButton("多重選擇"); ?? ?? panel.add(b); ?? b.addActionListener(this); ?? ?? label=new JLabel("你選取:"); ?? ?? Container contentPane=f.getContentPane(); ?? contentPane.add(panel,BorderLayout.NORTH); ?? contentPane.add(s,BorderLayout.CENTER); ?? contentPane.add(label,BorderLayout.SOUTH); ?? ?? f.setTitle("SelectionModelDemo"); ?? f.pack(); ?? f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); ?? } /*處理按鈕事件,利用ListSelectionModel界面所定義的setSelectionMode()方法來設置表格選取模式.*/ public void actionPerformed(ActionEvent e){ ?? if (e.getActionCommand().equals("單一選擇")) ?? selectionMode.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); ?? if (e.getActionCommand().equals("連續區間選擇")) ?? selectionMode.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); ?? if (e.getActionCommand().equals("多重選擇")) ?? selectionMode.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); ?? table.revalidate(); }
/*當用戶選取表格數據時會觸發ListSelectionEvent,我們實現ListSelectionListener界面來處理這一事件.ListSelectionListener界 *面只定義一個方法,那就是valueChanged(). */ ?? public void valueChanged(ListSelectionEvent el){ ?? String tempString=""; //JTable的getSelectedRows()與getSelectedColumns()方法會返回已選取表格cell的index Array數據. ?? int[] rows=table.getSelectedRows(); ?? int[] columns=table.getSelectedColumns();
//JTable的getValueAt()方法會返回某行的cell數據,返回值是Object數據類型,因此我們要自行轉成String數據類型. ?? for (int i=0;i<rows.length;i++){ ?? for (int j=0;j<columns.length;j++) tempString = tempString+" "+(String)table.getValueAt(rows[i], columns[j]); ?? } ?? label.setText("你選取:"+tempString); } public static void main(String[] args){ ?? new SelectionModelDemo(); } }
說明: 在此范例中,我們要處理ActionEvent與ListSelectionEvent,因此在程序中我們要實現ActionListenrer與ListSelectionListener界 面,而ListSelectionEvent是屬于Swing事件,因此程序中我們要import javax.swing.event package進來.
8-6:DefaultTableModel 我們曾提到過DefaultTableModel類,并說明了此類是繼承AbstractTableModel抽象類而來,且實現了getColumnCount(),getRowCount() 與getValueAt()3個方法.因此在實際的使用上,DefaultTableModel比AbstractTableModel要來得簡單許多,也較常被拿來使用 .DefaultTableModel內部使用Vector來使用表格的數據,若佻所要顯示的表格格式是比較單純的變化,筆者建議使用DefaultTableModel類會 來得方便也簡單許多.若佻所要顯示的數據模式非常復雜,例如我們所舉的成績表格外加學生選課信息等,像這類的表格通常顯示的信息會因 人面異,因此使用AbstractTableModel會比較容易設計些.
下面是DefaultTableModel的構造函數: DefaultTableModel():建立一個DefaultTableModel,里面沒有任何數據. DefaultTableModel(int numRows,int numColumns):建立一個指定行列數的DefaultTableModel. DefaultTableModel(Object[][] data,Object[] columnNames):建立一個DefaultTableModel,輸入數據格式為Object Array.系統會 自動調用setDataVector()方法來設置數據。 DefaultTableModel(Object[] columnNames,int numRows):建立一個DefaultTableModel,并具有Column Header名稱與行數信息。 DefaultTableModel(Vector columnNames,int numRows):建立一個DefaultTableModel,并具有column Header名稱與行數信息。 DefaultTableModel(Vector data,Vector columnNames):建立一個DefaultTableModel,輸入數據格式為Vector.系統會自動調用 setDataVector()方法來設置數據。
DefaultTableModel類提供相當多好用的方法,如之前我們談論過的getColumnCount(),getRowCount(),getValueAt(),isCellEditable() setValueAt()等方法,均可直接使用。且DefaultTableModel也提供了addColumn()與addRow()等方法,可讓我們隨時增加表格的數據。下 面我們就舉一個動態增加表格字段的例子:
import java.awt.*; import java.awt.event.*; import java.util.Vector; import javax.swing.*; import javax.swing.event.*; import javax.swing.table.*;
public class AddRemoveCells implements ActionListener { JTable table = null; DefaultTableModel defaultModel = null;
public AddRemoveCells() { ??JFrame f = new JFrame(); ??String[] name = {"字段 1","字段 2","字段 3","字段 4","字段 5"}; ??String[][] data = new String[5][5]; ??int value =1; ??for(int i=0; i<data.length; i++) ??{ ?? for(int j=0; j<data[i].length ; j++) ?? data[i][j] = String.valueOf(value++); } ?? ??defaultModel = new DefaultTableModel(data,name); ??table=new JTable(defaultModel); ??table.setPreferredScrollableViewportSize(new Dimension(400, 80)); JScrollPane s = new JScrollPane(table);
JPanel panel = new JPanel(); JButton b = new JButton("增加行"); panel.add(b); b.addActionListener(this); b = new JButton("增加列"); panel.add(b); b.addActionListener(this); b = new JButton("刪除行"); panel.add(b); b.addActionListener(this); b = new JButton("刪除列"); panel.add(b); b.addActionListener(this);
Container contentPane = f.getContentPane(); contentPane.add(panel, BorderLayout.NORTH); contentPane.add(s, BorderLayout.CENTER);
?? f.setTitle("AddRemoveCells"); f.pack(); f.setVisible(true);
f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } /*要刪除列必須使用TableColumnModel界面定義的removeColumn()方法。因此我閃先由JTable類的getColumnModel()方法取得 *TableColumnModel對象,再由TableColumnModel的getColumn()方法取得要刪除列的TableColumn.此TableColumn對象當作是 *removeColumn()的參數。刪除此列完畢后必須重新設置列數,也就是使用DefaultTableModel的setColumnCount()方法來設置。 */ public void actionPerformed(ActionEvent e) { if(e.getActionCommand().equals("增加列")) defaultModel.addColumn("增加列"); if(e.getActionCommand().equals("增加行")) defaultModel.addRow(new Vector()); if(e.getActionCommand().equals("刪除列")) { int columncount = defaultModel.getColumnCount()-1; if(columncount >= 0)//若columncount<0代表已經沒有任何列了。 { TableColumnModel columnModel = table.getColumnModel(); TableColumn tableColumn = columnModel.getColumn(columncount); columnModel.removeColumn(tableColumn); defaultModel.setColumnCount(columncount); } } if(e.getActionCommand().equals("刪除行")) { int rowcount = defaultModel.getRowCount()-1;//getRowCount返回行數,rowcount<0代表已經沒有任何行了。 if(rowcount >= 0) { defaultModel.removeRow(rowcount); defaultModel.setRowCount(rowcount);//刪除行比較簡單,只要用DefaultTableModel的removeRow()方法即可。刪除 //行完畢后必須重新設置列數,也就是使用DefaultTableModel的setRowCount()方法來設置。 } } table.revalidate(); }
public static void main(String args[]) { new AddRemoveCells(); } }
|