2007年2月6日 星期二

[Java] 自訂JTable的cell內容

  這幾天,因為工作的需求必須要修改JTable的cell型態,讓他不只能顯示純文字,而能依照自己想要的方式顯示,因為JTable的架構設計得有點複雜,所以這個問題實在花了我不少時間研究,既然有了點研究結果,那就順便寫下來,這樣以後應該會比較方便。

  根據官方API文件的說法,JTable設計架構裡面的TableCellRenderer就像是個印章一樣,JTable中的每個cell都是依照被設定好的TableCellRenderer呈現內容,如果想要自訂JTable裡面的cell,有幾個不同的方法可以達成同樣的目的。比較常見的作法就是繼承Java API裡面已經設計好的DefaultTableCellRenderer並且override其中的public Component getTableCellRendererComponent( JTable,Object,boolean,boolean,int,int) method或是和我下面示範的作法一樣,直接拿內建的DefaultTableCellRenderer來使用,但是自訂其中的getTableCellRendererComponent()

  其實DefaultTableCellRenderer也就是一個JLabel,當我們把數字丟進JTable的時候,數字會自動被wrapInteger Object,而文字當然還是以String來表示,最後還是會交給DefaultTableCellRenderer這個JLabelsubclass做顯示的動作。進入要自訂getTableCellRendererComponent()的階段之後,必須要藉由parameter list上的Object value這個parameter取得cell的所存放的內容,之後就可以依據這個值做程式邏輯的判斷。

  如果想要自訂cell的顯示方式,可以參考parameter list上的row, col這兩個值來判斷是不是想要的cell,接著呼叫super.getTableCellRendererComponent()取得這個cell的Renderer Component,並且把它castJLabel,藉由JLabel的setForeground()、setBackground()等各項method更改顯示的樣式(使用setBackground()之前必須要先呼叫setOpaque(true))。甚至也可以不要用JLabel顯示,只要先使用java.awt.Component以下可以顯示的subclass自訂自己想要的顯示樣式,然後在return的時候丟回去給上層的架構就好了。

  以下的sample code示範了在JTable中傳入字串和數字,但是顯示出來的字串根據內容的不同有不同的顏色,而數字也是用JSlider的形式表示。

import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;

public class CellRendererDemo {
public CellRendererDemo() {
JFrame frame = new JFrame("JTable CellRenderer Demo");
JScrollPane scrollPane;

JTable table;
String [] columnNames = {"String value", "Slider value"};
DefaultTableModel tableModel =
new DefaultTableModel(columnNames, 0);

/* pseudo data */
Object data [][] = {
{"One", 1}, {"Two", 2}, {"Three", 3}, {"Four", 4},
{"Five", 5}, {"Six", 6}, {"Seven", 7}, {"Eight", 8},
{"Night", 9}, {"Ten", 10}
};

for(int i = 0 ; i < data.length ; i++) {
tableModel.addRow(data[i]);
}

table = new JTable(tableModel);
scrollPane = new JScrollPane(table);
scrollPane = new JScrollPane(table,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

DefaultTableCellRenderer renderer =
new DefaultTableCellRenderer() {
public Component getTableCellRendererComponent(
JTable table,Object value,
boolean isSelected, boolean hasFocus,
int row,int col) {

JLabel label = (JLabel)
super.getTableCellRendererComponent(
table, value, isSelected,
hasFocus, row, col);
label.setForeground(Color.black);

/* return value */
JComponent retComponent = null;

if( value instanceof String && col == 0 ) {
if( row < 5 ) {
label.setForeground(Color.blue);
}else {
label.setForeground(Color.red);
}
retComponent = label;
}else if( value instanceof Integer && col == 1) {
JSlider slider = new JSlider(0, 10);
slider.setValue(
((Integer)value).intValue() );
retComponent = slider;
}

return retComponent;
}
};

/* register the TableCellRenderer */
for(int i=0 ; i < table.getColumnCount() ; i++) {
table.getColumnModel().getColumn(i).
setCellRenderer(renderer);
}

frame.getContentPane().add(scrollPane);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}

public static void main(String [] args) {
new CellRendererDemo();
}
}


TableCellRenderer Demo



沒有留言: