我有一个JTable,它的一个列中包含不同的对象类型。每个类型都有自己的渲染器和编辑器(getDefaultRenderer(Number.class),我自己的日期渲染器/编辑器等。)。
但是我的表模型中的方法setValueAt(Object value, int row, int col)
(我重写DefaultTableModel)总是将String作为value
。因此,尽管编辑器不同,但我无法在不解析字符串的情况下更新行,这不是一个好主意,因为我的表将来很容易处理其他对象类型。
getValueAt(int row, int col)
不会将对象转换为字符串。我检查了一下。这种行为的原因是什么?
编辑:以下代码。只有布尔单元格编辑器才能正常工作。
import java.awt.Component;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
public class Tabela {
public static void main(String[] args){
JFrame fr = new JFrame("tabela");
fr.setSize(600, 400);
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// custom renderer and editor for Date
final DateCellEditor dateEditor = new DateCellEditor();
final DateCellRenderer dateRenderer = new DateCellRenderer();
final TableModel model = new TableModel();
JTable table = new JTable(model){
public TableCellEditor getCellEditor(int row, int col){
if (model.getValueAt(row, col) instanceof Boolean)
return getDefaultEditor(Boolean.class);
else if (model.getValueAt(row, col) instanceof Number)
return getDefaultEditor(model.getValueAt(row, col).getClass());
else if (model.getValueAt(row, col) instanceof Date)
return dateEditor;
else return getDefaultEditor(Object.class);
}
public TableCellRenderer getCellRenderer(int row, int col){
if (model.getValueAt(row, col) instanceof Boolean)
return getDefaultRenderer(Boolean.class);
else if (model.getValueAt(row, col) instanceof Number)
return getDefaultRenderer(model.getValueAt(row, col).getClass());
else if (model.getValueAt(row, col) instanceof Date)
return dateRenderer;
else
return getDefaultRenderer(Object.class);
}
};
JScrollPane sc = new JScrollPane(table);
fr.getContentPane().add(sc);
fr.setVisible(true);
}
public static class TableModel extends DefaultTableModel{
// data in first column
private ArrayList<String> names = new ArrayList<String>();
// data in second column - can by any object
private ArrayList<Object> values = new ArrayList<Object>();
public TableModel(){
// insert example data
names.add("string value");
values.add("some string");
names.add("number value");
values.add(new Integer(12345));
names.add("Boolean value");
values.add(new Boolean(false));
names.add("Double value");
values.add(new Double(10.5));
names.add("Date object");
values.add(new Date(System.currentTimeMillis()));
}
public void setValueAt(Object value, int row, int col){
values.set(row, value);
fireTableCellUpdated(row, col);
}
public Object getValueAt(int row, int col){
if (col==0)
return names.get(row) + " ["+values.get(row).getClass().getSimpleName()+"]";
else return values.get(row);
}
public int getRowCount(){
if (values==null) return 0;
else return values.size();
}
public int getColumnCount(){
return 2;
}
public boolean isCellEditable(int row, int col){
return col==1; // only column 2 is editable
}
public Class<?> getColumnClass(int col){
switch(col){
case 0:
return String.class;
default:
return Object.class;
}
}
}
// My own renderer and editor for Date type
protected static class DateCellRenderer extends DefaultTableCellRenderer{
private static DateFormat format = new SimpleDateFormat("dd-MM-y HH:mm:ss");
public static void setDateFormat(String f){
format = new SimpleDateFormat(f);
}
public Component getTableCellRendererComponent (JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
if (value instanceof Date){
value = format.format(value);
}
else if(value instanceof Calendar)
{
Calendar dateValue = (Calendar) value;
value = format.format(dateValue.getTime());
}
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (c instanceof JComponent){
JComponent jc = (JComponent) c;
jc.setToolTipText("dd-MM-y HH:mm:ss");
}
return c;
}
}
protected static class DateCellEditor extends DefaultCellEditor{
private static DateFormat format = new SimpleDateFormat("dd-MM-y HH:mm:ss");
private JFormattedTextField textField = new JFormattedTextField(format);
public DateCellEditor(){
super(new JFormattedTextField(format));
}
public void setDateFormat(String f){
format = new SimpleDateFormat(f);
textField = new JFormattedTextField(format);
}
public Component getTableCellEditorComponent (JTable table, Object value, boolean isSelected, int row, int column)
{ System.out.println("editor: "+value.getClass());
if (value instanceof Date){
value = format.format(value);
}
else if(value instanceof Calendar)
{
Calendar dateValue = (Calendar) value;
value = format.format(dateValue.getTime());
}
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}
}
}
答案 0 :(得分:2)
从你的代码示例中可以(立即)有许多值得关注的事情。
首先,不应该覆盖getCellEditor
的{{1}}和getCellRenderer
方法。
如果模型中的值为JTable
,那么我对您完成此操作的最大问题是什么?
您可以使用null
和Class
方法修改单元格编辑器并渲染给定的setDefaultEditor(Class, TableCellEditor)
。
从表格模型中,您应该返回所需的所有setDefaultRenderer(Class, TableCellRenderer)
类型的所需列(来自Class
)。这里的假设是给定列具有相同类型的getColumnClass
值。
但是,问题的原因在于编辑器。
如果示例编辑器可以使用,那么您将从Class
扩展,它只使用DefaultCellEditor
作为编辑器。这意味着JTextField
将返回getCellEditorValue
,因此String
方法传递的值为setValueAt
。
有很多选择。
String
使用更合适的编辑器(例如TableCellEditor
或JSpinner
)JCheckBox
,将getCellEditorValue
值从默认编辑器转换为更合适的String
类型。我更喜欢选项1,因为它代表了适合的表单和编辑器中的底层数据,并且在处理错误的解析时会带来很多麻烦。
我会仔细查看How to use tables并密切关注自定义编辑器的各个部分
答案 1 :(得分:1)
清理我可能在评论中传播的混淆:如果你在一列中有不同类别的值
一些片段
// override in JTable
@Override
public TableCellRenderer getCellRenderer(int row, int column) {
// use the per-column renderer if available
TableColumn tableColumn = getColumnModel().getColumn(column);
TableCellRenderer renderer = tableColumn.getCellRenderer();
// if the column didn't provide a renderer and has type Object.class
if (renderer == null && Object.class.equals(getColumnClass(column))) {
Object value = getValueAt(row, column);
if (value != null) {
renderer = getDefaultRenderer(value.getClass());
}
}
if (renderer == null) {
// shouldn't happen, but fixing super bug
renderer = getDefaultRenderer(Object.class);
}
return renderer;
}
答案 2 :(得分:0)
由于多种原因,返回的对象不能是字符串:
一个Object to String转换器很容易做到,但是String to Object将很难以通用方式编写。