更新
当columnClass为Double(错误ID:7051636)时,JTable上已确认为错误,无法将给定的Object格式化为Number。请随意投票支持,或者如果你有其他(更好的)解决方案,请将其作为评论发布到报告中。
我正在构建一个JTable,它具有扩展AbstractTableModel构建的自定义表模型。我的模型需要支持空行来显示和排序。所以我遵循这篇文章来实现它,现在工作得很好。
在JTable中格式化字段时,我仍然有一个问题。假设我有以下模型:
public class MyModel extends AbstractTableModel{
public Object[] types= {new Integer(0), ""};
public static final Object EMPTY_ROW = "";
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return this.EMPTY_ROW;
}
public Class<? extends Object> getColumnClass(int c) {
if (c > this.types.length - 1)
return null;
else
return this.types[c].getClass();
}
}
一切都很好。但是如果我有一个Double而不是Integer:
public class MyModel extends AbstractTableModel{
public Object[] types= {new Double(0.0), ""};
.......
我将得到一个非法参数异常:
编辑:@Aaron Digulla建议后的新堆栈跟踪输出
线程"AWT-EventQueue-0"java.lang.IollegalArgumentException中的异常:无法将给定对象格式化为数字在java.text.DecimalFormat.format(DecimalFormat.java:487)在java.text.Format.Format(Format.java:140)位于javax.swing.JTable$DoubleRenderer.setValue(JTable.java:5352)位于javax.swing.table.DefaultTableCellRenderer.getTableCellRenderComponent(DefaultTableCellRender.java:237)位于javax.swing.JTable.prepareRenderer(JTable.java:5720)位于javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2072)位于javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:1974)位于javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1770)位于javax.swing.plaf.ComponentUI.update(ComponentUI.java:143)位于javax.swing.JComponent.paintComponent.java:752)位于javax.swing.JComponent.paint(JComponent-java:1029)位于javax.swing.JComponent.paintChildren(JComponent.java:862)位于javax.swing.JComponent.paint(JComponent-java:1038)位于javax.swing.JViewport.paint(JViewport.java:747)位于javax.swing.JComponent.paintChildren(JComponent.java:862)位于javax.swing.JComponent.paint(JComponent-java:1038)位于javax.swing.JComponent.paintChildren(JComponent.java:862)位于javax.swing.JComponent.paint(JComponent-java:1038)位于javax.swing.JComponent.paintChildren(JComponent.java:862)位于javax.swing.JComponent.paint(JComponent-java:1038)位于javax.swing.JLayeredPane.paint(JLayeredPane.java:567)位于javax.swing.JComponent.paintChildren(JComponent.java:862)位于javax.swing.JComponent.painToOffscreen(JComponent.java:5131)位于javax.swing.BufferStrategyPaint Manager.paint(BufferStrategyPaint Manager.java:278)位于javax.swing.RepaintManager.paint(RepaintManager.java:1224)位于javax.swing.JComponent.paint(JComponent.java:1015)在java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallack.java:21)位于sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallack.java:60)位于sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallack.java:97)位于java.awt.Container.paint(Container.java:1780)位于java.awt.Window.paint(Window.java:3375)位于javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:796)位于javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:713)位于javax.swing.RepaintManager.seqPaintDirtyRegions(RepaintManager.java:693)位于javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:125)在java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)位于java.awt.EventQueue.dispatchEvent(EventQueue.java:597)位于java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)位于java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)位于java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)位于java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)位于java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)在java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
为什么?
getValueAt总是返回相同的值来填充所有表条目。这仅用于调试:
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return this.EMPTY_ROW;
}
例如,如果我更改为:
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return new Integer(3);
//or return new Double(3.3);
//return new String("foobar"); doesn't work
}
即使表中的某个字段是String,一切都可以正常工作。它向我暗示,因为Integer和Double可以转换为String,这不会造成问题。无论如何,我想理解为什么像我的EMPTY_ROW这样的泛型对象可以被接受为声明的Integer字段的值,而这不适用于Double字段。
第2版:
如果在表模型中删除getClass方法。它有效。无论如何,我想在不必删除该方法的情况下解决这个问题,即使这将迫使我实现一些自定义渲染方法。
第3版:
这是SSCCE。向表中添加新值时出现了一些错误,但与渲染问题无关。
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Comparator;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SortOrder;
import javax.swing.RowSorter.SortKey;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;
public class TableExample extends JFrame{
public static final Object EMPTY_ROW = "";
public class EmptyRowComparator<COLUMN_TYPE extends Comparable<COLUMN_TYPE>> implements Comparator<Object>{//extends RuleBasedCollator{
private TableRowSorter<? extends AbstractTableMod> sorter;
private int column;
public EmptyRowComparator(TableRowSorter<? extends AbstractTableMod> sorter, int col) throws ParseException {
// super(arg0);
this.sorter = sorter;
this.column = col;
// TODO Auto-generated constructor stub
}
private int getSortOrder() {
SortOrder order = SortOrder.ASCENDING;
// List<? extends SortKey> keys = sorter.getSortKeys();
// sorter.getSortKeys();
//
for (SortKey sortKey : sorter.getSortKeys()) {
if (sortKey.getColumn() == this.column) {
order = sortKey.getSortOrder();
break;
}
}
return order == SortOrder.ASCENDING ? 1 : -1;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return 0;
}
@Override
public int compare(Object arg0, Object arg1) {
// TODO Auto-generated method stub
//System.out.println("Comparing Integer arg0 " + arg0 + " arg1 " + arg1);
boolean empty1 = arg0 == EMPTY_ROW;
boolean empty2 = arg1 == EMPTY_ROW;
if (empty1 && empty2) {
return 0;
}
else if (empty1) {
return 1 * getSortOrder();
}
else if (empty2) {
return -1 * getSortOrder();
}
return ((Comparable<COLUMN_TYPE>) (COLUMN_TYPE)arg0).compareTo((COLUMN_TYPE)arg1);
// return 0;
}
}
public class ConcreteTable extends AbstractTableMod{
//
private static final long serialVersionUID = 4672561280810649603L;
private String[] columnNames = {"ID",
"description"};
Class[] types = {Integer.class, String.class};
//Object[] types = {Double.class, String.class};
private int minimumDisplayedRow;
public ConcreteTable(){
//System.out.println("DEBUG ARRAY length " + data.length);
this.minimumDisplayedRow = 10;
this.datas = new ArrayList<ArrayList<Object>>();
for (int i = 0 ; i < this.minimumDisplayedRow ; i++){
this.addEmptyRow();
}
for (int i = 0 ; i < 5 ; i++){
ArrayList<Object> row = new ArrayList<Object>();
row.add(new Integer(i));
row.add(new String("prova " + i));
this.addRow(row);
}
}
public String getColumnName(int col) {
System.out.println("getColumnName " + col + " = " + columnNames[col]);
return columnNames[col];
}
@Override
protected Class[] getTypeArray() {
// TODO Auto-generated method stub
return this.types;
}
@Override
protected ArrayList<Integer> getKeysColumnIndex() {
// TODO Auto-generated method stub
ArrayList<Integer> keys = new ArrayList<Integer>();
keys.add(0);
return keys;
}
public boolean isCellEditable(int row, int col) {
System.out.println("isCellEditable row " + row + " col " + col);
if (col == 1){
System.out.println("TRUE");
return true;
}
return false;
}
/*note: generated keys must be in the same order they appear in the table*/
@Override
protected Object getGeneratedKeys(int col) {
// TODO Auto-generated method stub
if (col != 0 )
return null;
return new Integer(this.rowNumber);
}
@Override
protected int getMinimumDisplayedRow() {
// TODO Auto-generated method stub
return this.minimumDisplayedRow;
}
}
public abstract class AbstractTableMod extends AbstractTableModel {
ArrayList<ArrayList<Object>> datas ;
protected int rowNumber = 0;
protected abstract Class[] getTypeArray();
protected abstract ArrayList<Integer> getKeysColumnIndex();
protected abstract Object getGeneratedKeys(int col);
protected abstract int getMinimumDisplayedRow();
public int getRowCount(){
return this.datas.size() ;
}
@Override
public int getColumnCount() {
return this.getTypeArray().length;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (rowIndex >= this.rowNumber ){
return EMPTY_ROW;
}
try{
ArrayList<Object> row = this.datas.get(rowIndex);
if (row == null)
return null;
Object obj = row.get(columnIndex);
return obj;
}catch(IndexOutOfBoundsException e){
return null;
}
}
public void setValueAt(Object value, int row, int col) {
//System.out.println("setValueAt object : " + value.getClass().getName());
Class<? extends Object> targetColClass = this.getColumnClass(col);
if (!targetColClass.isInstance(value))
return;
if (value instanceof String){
String stringVal = (String)value;
if (stringVal.compareTo("") == 0)
return;
}
if (row >= this.rowNumber){
ArrayList<Object> newRow = new ArrayList<Object>();
ArrayList<Integer> keysIndexList = this.getKeysColumnIndex();
for (int i = 0 ; i < this.getColumnCount(); i++){
if (i == col){
newRow.add(value);
}else if (keysIndexList.contains(i)){
newRow.add(this.getGeneratedKeys(i));
}else{
newRow.add(EMPTY_ROW);
}
}
this.addRow(newRow);
}else{
this.datas.get(row).set(col, value);
}
this.fireTableCellUpdated(row, col);
}
public Class<? extends Object> getColumnClass(int c) {
System.out.println("AbstractTable: getColumnClass");
if (c > this.getTypeArray().length - 1)
return null;
else
return this.getTypeArray()[c];
}
public void addEmptyRow(){
ArrayList<Object> emptyRow = new ArrayList<Object>();
for (int i = 0 ; i < this.getTypeArray().length; i++){
emptyRow.add(EMPTY_ROW);
}
this.datas.add(emptyRow);
}
public void addRow(ArrayList<Object> row){
Object[] types = this.getTypeArray();
if (types.length != row.size())
return;
for (int i = 0 ; i < row.size() ; i++){
Class<? extends Object> targetColClass = this.getColumnClass(i);
Object rowItem = row.get(i);
}
this.datas.add(this.rowNumber, row);
this.rowNumber++;
if (this.rowNumber < this.getMinimumDisplayedRow())
this.datas.remove(this.datas.size() -1 );
this.fireTableRowsInserted(this.rowNumber , this.rowNumber );
}
}
public TableExample(){
super("JTable example");
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
ConcreteTable model = new ConcreteTable();
JTable tab = new JTable(model);
TableRowSorter<ConcreteTable> sorter = new TableRowSorter<ConcreteTable>(model);
try {
sorter.setComparator(0, new EmptyRowComparator<Integer>(sorter,0));
sorter.setComparator(1, new EmptyRowComparator<String>(sorter,1));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
tab.setRowSorter(sorter);
JScrollPane table = new JScrollPane(tab);
this.getContentPane().add(table);
this.setSize(600, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
new TableExample();
}
}
如果您尝试更改
Class[] types = {Integer.class, String.class};
带有:
Class[] types = {Double.class, String.class};
你可以看到问题所在。
Walter Laan
在他的线程中是如何说的
Never give up! Never surrender!
编辑:我忍不住了,但由于我的英语不好,我不敢评论为什么、在哪里以及如何做到这一点,也不敢正确地进行验证。我为TableColumnRendering添加了Rob的两个(稍微)修改过的类。。。,
import java.awt.EventQueue;
import java.math.RoundingMode;
import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.RowSorter.SortKey;
import javax.swing.SwingConstants;
import javax.swing.table.*;
public class TableExample extends JFrame {
public static final Object EMPTY_ROW = "";
private static final long serialVersionUID = 1L;
private JTable tab;
private Calendar cal;
private Date dateWithOutTime = new java.util.Date();
private SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");//standard continental EU date format
public class EmptyRowComparator<COLUMN_TYPE extends Comparable<COLUMN_TYPE>> implements Comparator<Object> {//extends RuleBasedCollator{
private TableRowSorter<? extends AbstractTableMod> sorter;
private int column;
public EmptyRowComparator(TableRowSorter<? extends AbstractTableMod> sorter, int col) throws ParseException {
this.sorter = sorter;
this.column = col;
}
private int getSortOrder() {
SortOrder order = SortOrder.ASCENDING;
for (SortKey sortKey : sorter.getSortKeys()) {
if (sortKey.getColumn() == this.column) {
order = sortKey.getSortOrder();
break;
}
}
return order == SortOrder.ASCENDING ? 1 : -1;
}
@Override
public int hashCode() {
return 0;
}
@Override
@SuppressWarnings("unchecked")
public int compare(Object arg0, Object arg1) {
boolean empty1 = arg0 == EMPTY_ROW;
boolean empty2 = arg1 == EMPTY_ROW;
if (empty1 && empty2) {
return 0;
} else if (empty1) {
return 1 * getSortOrder();
} else if (empty2) {
return -1 * getSortOrder();
}
return ((Comparable<COLUMN_TYPE>) (COLUMN_TYPE) arg0).compareTo((COLUMN_TYPE) arg1);
}
}
public class ConcreteTable extends AbstractTableMod {
private static final long serialVersionUID = 4672561280810649603L;
private String[] columnNames = {"Integer", "String", "Integer", "Double", "Boolean", "Double", "String", "Boolean", "Date"};
private Class<?>[] types = {Integer.class, String.class, String.class, String.class, String.class,
String.class, String.class, String.class, String.class};
private int minimumDisplayedRow;
public ConcreteTable() {
this.minimumDisplayedRow = 10;
this.datas = new ArrayList<ArrayList<Object>>();
for (int i = 0; i < this.minimumDisplayedRow; i++) {
this.addEmptyRow();
}
Random rnd = new Random();
for (int i = 0; i < 7; i++) {
ArrayList<Object> row = new ArrayList<Object>();
row.add(i);
row.add(((rnd.nextInt(25)) + "prova"));
row.add(rnd.nextInt(25));
row.add(rnd.nextInt(25) + 3.14);
row.add((i % 2 == 0) ? true : false);
row.add(rnd.nextInt(25) + 3.14);
row.add(((rnd.nextInt(25)) + "prova"));
row.add((i % 2 == 0) ? false : true);
cal = Calendar.getInstance();
cal.add(Calendar.DATE, -rnd.nextInt(25));
dateWithOutTime = cal.getTime();
String nullTimeForDateString = sdf.format(dateWithOutTime);
try {
dateWithOutTime = sdf.parse(nullTimeForDateString);
} catch (ParseException ex) {
}
row.add(dateWithOutTime);
this.addRow(row);
}
}
@Override
public String getColumnName(int col) {
System.out.println("getColumnName " + col + " = " + columnNames[col]);
return columnNames[col];
}
@Override
protected Class<?>[] getTypeArray() {
return this.types;
}
@Override
protected ArrayList<Integer> getKeysColumnIndex() {
ArrayList<Integer> keys = new ArrayList<Integer>();
keys.add(0);
return keys;
}
@Override
public boolean isCellEditable(int row, int col) {
System.out.println("isCellEditable row " + row + " col " + col);
if (col == 1) {
System.out.println("TRUE");
return true;
}
return false;
}
@Override
protected Object getGeneratedKeys(int col) {
if (col != 0) {
return null;
}
return new Integer(this.rowNumber);
}
@Override
protected int getMinimumDisplayedRow() {
return this.minimumDisplayedRow;
}
}
public abstract class AbstractTableMod extends AbstractTableModel {
private static final long serialVersionUID = 1L;
protected ArrayList<ArrayList<Object>> datas;
protected int rowNumber = 0;
protected abstract Class<?>[] getTypeArray();
protected abstract ArrayList<Integer> getKeysColumnIndex();
protected abstract Object getGeneratedKeys(int col);
protected abstract int getMinimumDisplayedRow();
public int getRowCount() {
return this.datas.size();
}
@Override
public int getColumnCount() {
return this.getTypeArray().length;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (rowIndex >= this.rowNumber) {
return EMPTY_ROW;
}
try {
ArrayList<Object> row = this.datas.get(rowIndex);
if (row == null) {
return null;
}
Object obj = row.get(columnIndex);
return obj;
} catch (IndexOutOfBoundsException e) {
return null;
}
}
@Override
public void setValueAt(Object value, int row, int col) {
Class<? extends Object> targetColClass = this.getColumnClass(col);
if (!targetColClass.isInstance(value)) {
return;
}
if (value instanceof String) {
String stringVal = (String) value;
if (stringVal.compareTo("") == 0) {
return;
}
}
if (row >= this.rowNumber) {
ArrayList<Object> newRow = new ArrayList<Object>();
ArrayList<Integer> keysIndexList = this.getKeysColumnIndex();
for (int i = 0; i < this.getColumnCount(); i++) {
if (i == col) {
newRow.add(value);
} else if (keysIndexList.contains(i)) {
newRow.add(this.getGeneratedKeys(i));
} else {
newRow.add(EMPTY_ROW);
}
}
this.addRow(newRow);
} else {
this.datas.get(row).set(col, value);
}
this.fireTableCellUpdated(row, col);
}
@Override
@SuppressWarnings("unchecked")
public Class<? extends Object> getColumnClass(int c) {
if (c > this.getTypeArray().length - 1) {
return null;
} else {
return this.getTypeArray()[c];
}
}
public void addEmptyRow() {
ArrayList<Object> emptyRow = new ArrayList<Object>();
for (int i = 0; i < this.getTypeArray().length; i++) {
emptyRow.add(EMPTY_ROW);
}
this.datas.add(emptyRow);
}
public void addRow(ArrayList<Object> row) {
Object[] types = this.getTypeArray();
if (types.length != row.size()) {
return;
}
for (int i = 0; i < row.size(); i++) {
Class<? extends Object> targetColClass = this.getColumnClass(i);
Object rowItem = row.get(i);
}
this.datas.add(this.rowNumber, row);
this.rowNumber++;
if (this.rowNumber < this.getMinimumDisplayedRow()) {
this.datas.remove(this.datas.size() - 1);
}
this.fireTableRowsInserted(this.rowNumber, this.rowNumber);
}
}
public TableExample() {
super("JTable example");
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
ConcreteTable model = new ConcreteTable();
tab = new JTable(model);
TableRowSorter<ConcreteTable> sorter = new TableRowSorter<ConcreteTable>(model);
try {
sorter.setComparator(0, new EmptyRowComparator<Integer>(sorter, 0));
sorter.setComparator(1, new EmptyRowComparator<String>(sorter, 1));
sorter.setComparator(2, new EmptyRowComparator<String>(sorter, 2));
sorter.setComparator(3, new EmptyRowComparator<String>(sorter, 3));
sorter.setComparator(4, new EmptyRowComparator<String>(sorter, 4));
sorter.setComparator(5, new EmptyRowComparator<String>(sorter, 5));
sorter.setComparator(6, new EmptyRowComparator<String>(sorter, 6));
sorter.setComparator(7, new EmptyRowComparator<String>(sorter, 7));
sorter.setComparator(8, new EmptyRowComparator<String>(sorter, 8));
} catch (ParseException e) {
e.printStackTrace();
}
tab.setRowSorter(sorter);
JScrollPane table = new JScrollPane(tab);
this.getContentPane().add(table);
this.setSize(800, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setRenderers();
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
setVisible(true);
}
});
//TableExample tableExample = new TableExample();
}
public void setRenderers() {
TableColumnModel m = tab.getColumnModel();
//"Integer", "String", "Interger", "Double", "Boolean", "Double", "String", "Boolean", "Date"
m.getColumn(0).setCellRenderer(NumberRenderer.getIntegerRenderer());
m.getColumn(2).setCellRenderer(NumberRenderer.getIntegerRenderer());
m.getColumn(3).setCellRenderer(NumberRenderer.getDoubleRenderer5());
m.getColumn(5).setCellRenderer(NumberRenderer.getDoubleRenderer3());
m.getColumn(8).setCellRenderer(FormatRenderer.getDateRenderer());
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
TableExample tableExample = new TableExample();
}
});
TableExample tableExample = new TableExample();
}
}
class FormatRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
private Format formatter;
private static DateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");//standard continental EU date format
FormatRenderer(Format formatter) {
this.formatter = formatter;
}
@Override
public void setValue(Object value) {
try {
if ((value != null)) {
if ((value instanceof Number) || (value instanceof Date)) {
setHorizontalAlignment(SwingConstants.RIGHT);
value = formatter.format(value);
}
}
} catch (IllegalArgumentException e) {
}
super.setValue(value);
}
public static FormatRenderer getDateRenderer() {
return new FormatRenderer(dateFormat);
}
}
class NumberRenderer extends FormatRenderer {
private static final long serialVersionUID = 1L;
private static Number numberValue;
private static NumberFormat nf;
NumberRenderer(NumberFormat formatter) {
super(formatter);
setHorizontalAlignment(SwingConstants.RIGHT);
}
public static NumberRenderer getIntegerRenderer() {
return new NumberRenderer(NumberFormat.getIntegerInstance());
}
public static NumberRenderer getDoubleRenderer3() {
nf = NumberFormat.getNumberInstance();
nf.setMinimumFractionDigits(3);
nf.setMaximumFractionDigits(3);
nf.setRoundingMode(RoundingMode.HALF_UP);
return new NumberRenderer(nf);
}
public static NumberRenderer getDoubleRenderer5() {
nf = NumberFormat.getNumberInstance();
nf.setMinimumFractionDigits(5);
nf.setMaximumFractionDigits(5);
nf.setRoundingMode(RoundingMode.HALF_UP);
return new NumberRenderer(nf);
}
}
实际问题与之前的辩论有关,有普通的香草(比较我缺失的英语技能),你认为这真的是Bug吗?或者如果我展示了ViceVersaView,也许有人可以用英语评论JTable+TableModel+Comprator(JTableneneneba API的TableRowSorter)的链,eeeeee rghhh在这种情况下真的很糟糕
import java.awt.*;
import java.awt.event.*;
import java.util.Date;
import javax.swing.*;
import javax.swing.table.*;
public class ViceVersaBugFromTableModelAndComparator {
private String[] columnNames = {"String", "Integer", "Boolean", "Double", "Date"};
private Object[][] data = {
{"aaa", 12, true, .15, new Date()},
{"bbb", 5, false, 100.01, new Date()},
{"CCC", 92, true, 15.2, new Date()},
{"DDD", 0, false, 10.80, new Date()},
{"abc", 5, true, 4.11, new Date()},
{"bae", 31, false, 100.01, new Date()},
{"CAX", 27, true, 2.3, new Date()},
{"AXD", 4, false, 50.00, new Date()},
{"abc", 3, true, 1.5, new Date()},
{"bae", 5, false, 1000, new Date()}, //java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String
//{"bae", 5, false, 1000.0, new Date()}, //un-comment for correctness
{"CAX", 2, true, 21.7, new Date()},
{"AXD", 2, false, 5.30, new Date()}
};
private TableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
@Override
public Class<?> getColumnClass(int column) {
return String.class;// again java.lang.ClassCastException
//return getValueAt(0, column).getClass(); //un-comment for correctness
}
};
private JTable table = new JTable(model);
private JTableHeader header;
static class TestTableRowSorter extends TableRowSorter<TableModel> {
public TestTableRowSorter(TableModel m) {
super(m);
}
@Override
public void toggleSortOrder(int column) {
}
public void wrapToggleSortOrder(int column) {
super.toggleSortOrder(column);
}
}
private Timer timer = new Timer(400, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("single");
JTable table = header.getTable();
RowSorter sorter;
if (pt != null && table != null && (sorter = table.getRowSorter()) != null) {
int columnIndex = header.columnAtPoint(pt);
if (columnIndex != -1) {
columnIndex = table.convertColumnIndexToModel(columnIndex);
((TestTableRowSorter) sorter).wrapToggleSortOrder(columnIndex);
}
}
}
});
private Point pt;
public JComponent makeUI() {
timer.setRepeats(false);
table.setRowSorter(new TestTableRowSorter(model));
header = table.getTableHeader();
header.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(final MouseEvent e) {
if (timer.isRunning() && !e.isConsumed() && e.getClickCount() > 1) {
System.out.println("double");
pt = null;
timer.stop();
} else {
pt = e.getPoint();
timer.restart();
}
}
});
JPanel p = new JPanel(new BorderLayout());
p.add(new JScrollPane(table));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new ViceVersaBugFromTableModelAndComparator().makeUI());
f.setSize(820, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
问题不在于双精度,而在于其他方面。正如您在堆栈跟踪中看到的,该表特别支持双值(javax.swing.JTable$DoubleRenderer
)。
问题是传递给setValue()
的值不是Double
,而是其他值。
问题是:当您格式化Double值时,它变成了一个字符串,您不能将其返回,因为该列只允许Double.class。因此,如果您将Double.class更改为string.class,它将起作用。