概述
JTable通过TableCellRenderer和TableCellEditor这两个接口实现每个单元格的渲染和编辑,这两个接口都各有一个方法可以返回JComponent的子类,例如BooleanRenderer对应的是Boolean类型的数据,getTableCellRendererComponent返回的是JCheckBox:
class BooleanRenderer extends JCheckBox implements TableCellRenderer, UIResource
{
private final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public BooleanRenderer() {
super();
setHorizontalAlignment(JLabel.CENTER);
setBorderPainted(true);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
}
else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setSelected((value != null && ((Boolean)value).booleanValue()));
if (hasFocus) {
setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
} else {
setBorder(noFocusBorder);
}
return this; //返回自己,也就是JCheckBox
}
}
从如上代码中可以看出,getTableCellRendererComponent方法(TableCellRenderer中的唯一方法)返回的Component就是一个JCheckBox,因此使用个Renderer会在表格的单元格中显示一个勾选框。
只有Renderer只能显示静态数据,如果需要支持对数据进行编辑,那么必须同时实现Editor,不然点击单元格进行编辑时会使用默认的Editor,而默认的Editor使用的是JTextField,所以就会发现点完之后变成“true”和“false”了:
如果只实现Editor也不行,会变成只有在点击的时候显示成Checkbox,其他时候是文本框。
整体设计
在本博客中,我们要实现通过自定义的类型,让JTable用不同的UI组件进行显示,并支持根据数据模型的状态改变单元格的背景色。
设计思路是定义一个MColoredValue类,该类用于保存数据以及保存是否添加背景色。
public class MColoredValue<T> {
T value;
boolean colored;
public MColoredValue(T v, boolean colored){
this.value = v;
this.colored = colored;
}
public T getValue() {
return value;
}
public boolean isColored() {
return colored;
}
public void setValue(T value) {
this.value = value;
}
public void setColored(boolean colored) {
this.colored = colored;
}
@Override
public String toString() {
return ""+value;
}
}
根据我们的设计,如果isColored为true,那么给单元格使用红色背景色,否则用白色。然后我们的数据又分Boolean类型和String类型,我们希望Boolean类型使用CheckBox的形式来显示,String就用默认的文本框来显示。
public class MColoredBoolValue extends MColoredValue<Boolean> {
public MColoredBoolValue(Boolean v, boolean colored){
super(v, colored);
}
@Override
public boolean isColored(){
return this.value;
}
}
public class MColoredStringValue extends MColoredValue<String> {
public MColoredStringValue(String v, boolean colored){
super(v, colored);
}
}
然后我们实现TableCellRenderer和TableCellEditor接口,但只作为一个壳来使用,在JTable调用getTableCellRendererComponent和getTableCellEditorComponent实例化具体的类,例如如果传入的是MColoredBoolValue类型,那么我们就实例化对应的BooleanRenderer和BooleanEditor,否则用默认的Renderer和Editor。
TableCellRenderer
TableCellRenderer接口中只有getTableCellRendererComponent这一个方法,该方法会传入一个Object类型的参数,该参数就是我们设置到JTable某个单元格里面的值,因此我们可以通过判断这个参数的类型来选择使用不同的Renderer,比如Boolean类型可以用勾选框或下拉框来显示。
import java.awt.Color;
import java.awt.Component;