JTable中的问题格式化字段 - Integer和Double之间的差异 [英] problem formatting fields in a JTable - differences between Integer and Double

查看:152
本文介绍了JTable中的问题格式化字段 - Integer和Double之间的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新



确认为当ColumnClass为Double时,JTable不能将给定的Object格式化为Number(错误ID:7051636)。请随意投票,或者如果您有替代(更好的)解决方法,请将其作为对报告的评论。






我正在使用建立扩展AbstractTableModel的自定义表模型构建JTable。
我的模型需要支持空行显示和排序。
所以我接下来这个
post 实现,现在工作很好。



我仍然有一个问题,在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<?扩展对象> getColumnClass(int c){
if(c> this.types.length - 1)
返回null;
else
return this.types [c] .getClass();

}
}

一切正常。
但是如果我有一个Double而不是一个整数:

  public class MyModel extends AbstractTableModel {

public Object [] types = {new Double(0.0),};
.......

我会得到一个非法参数异常: / p>

编辑:
@Aaron Digulla建议后的新堆栈跟踪输出


线程中的异常AWT-EventQueue-0java.lang.IllegalArgumentException:不能将给定的Object格式作为数字
在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.getTableCellRendererComponent(DefaultTableCellRenderer。 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.Comp onentUI.update(ComponentUI.java:143)
javax.swing.JComponent.paintComponent(JComponent.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.paintToOffscreen(JComponent.java:5131)
在javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:278)
在javax.swing.RepaintManager.paint(RepaintManager.java:1224)
在javax.swing.JComponent.paint (JComponent.java:1015)
在java.awt.GraphicsCallback $ PaintCallback.run(GraphicsCallback.java:21)
在sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:60)
在sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:97)
在java.awt.Container.paint(Container.java:1780)
在java.awt.Window.paint(窗口。 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.even t.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);
//或返回新的Double(3.3);
// return new String(foobar);不工作
}

所有工作正常,即使表的某些字段是String 。它建议我,因为
一个整数和一个双重可以转换成字符串,这不会造成问题。
无论如何,我想了解为什么像我的EMPTY_ROW一样的通用对象可以接受为声明的整数字段的值,而这不适用于双字段。



EDIT2:



如果我在我的表模型中删除了getClass方法。有用。无论如何,我想解决这个问题,而不必删除该方法,即使这将迫使我实现一些自定义的渲染方法。



EDIT3:



这是一个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>>实现比较器< Object> {//扩展RuleBasedCollat​​or {

private TableRowSorter<?扩展AbstractTableMod>分拣机;
private int column;

public EmptyRowComparator(TableRowSorter<?extends AbstractTableMod> sorter,int col)throws ParseException {
// super(arg0);
this.sorter = sorter;
this.column = col;
// TODO自动生成的构造函数存根
}



private int getSortOrder(){
SortOrder order = SortOrder.ASCENDING;
//列表<?扩展SortKey> keys = sorter.getSortKeys();
// sorter.getSortKeys();
//

(SortKey sortKey:sorter.getSortKeys()){
if(sortKey.getColumn()== this.column){
order = sortKey.getSortOrder();
break;
}
}
返回订单== SortOrder.ASCENDING? 1:-1;
}



@Override
public int hashCode(){
// TODO自动生成的方法stub
return 0;
}

@Override
public int compare(Object arg0,Object arg1){
// TODO自动生成的方法stub
//系统。 out.println(比较整数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};


类[] 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>>(); (int i = 0; i< this.minimumDisplayedRow; i ++){
this.addEmptyRow();
(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自动生成的方法存根
返回this.types;
}

@Override
protected ArrayList< Integer> getKeysColumnIndex(){
// TODO自动生成的方法stub
ArrayList< Integer> keys = new ArrayList< Integer>();
keys.add(0);
返回键;
}
public boolean isCellEditable(int row,int col){
System.out.println(isCellEditable row+ row +col+ col);
if(col == 1){
System.out.println(TRUE);
返回true;
}

return false;
}
/ *注意:生成的键必须与表中出现的顺序相同* /
@Override
protected Object getGeneratedKeys(int col){
// TODO自动生成的方法stub
if(col!= 0)
return null;
return new Integer(this.rowNumber);
}
@Override
protected int getMinimumDisplayedRow(){
// TODO自动生成的方法存根
返回this.minimumDisplayedRow;
}




public abstract class AbstractTableMod extends AbstractTableModel {


ArrayList< ArrayList< Object> ;>数据;
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()。
}

@Override
public Object getValueAt(int rowIndex,int columnIndex){

if(rowIndex> = this.rowNumber){
返回EMPTY_ROW;
}

try {

ArrayList< Object> row = this.datas.get(rowIndex);
if(row == null)
返回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<?扩展对象> 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(); (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<?扩展对象> 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>(); (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; (int i = 0; i< row.size(); i ++){
Class<?扩展对象> targetColClass = this.getColumnClass(i);
对象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自动生成的catch块
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-生成方法stub
new TableExample();
}

}

如果您尝试更改



  Class [] types = {Integer.class,String.class}; 

with:

 code> Class [] types = {Double.class,String.class}; 

您可以看到问题。

解决方案

Walter Laan

 永不放弃!决不投降! 

编辑:我不能抵制,但由于我英文不好,我不敢评论为什么,在哪里和如何可能,也不正确工作,为确认我添加了Rob的两个(一点点)修改的类为TableColumnRendering ...,

  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;
私人JTable标签;
私人日历cal;
private Date dateWithOutTime = new java.util.Date();
private SimpleDateFormat sdf = new SimpleDateFormat(dd.MM.yyyy); //标准欧洲大陆欧盟日期格式

public class EmptyRowComparator< COLUMN_TYPE extends Comparable< COLUMN_TYPE>>实现比较器< Object> {// extends RuleBasedCollat​​or {

private TableRowSorter<?扩展AbstractTableMod>分拣机;
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;
(SortKey sortKey:sorter.getSortKeys()){
if(sortKey.getColumn()== this.column){
order = sortKey.getSortOrder();
break;
}
}
返回订单== 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,I​​nteger,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>>(); (int i = 0; i< this.minimumDisplayedRow; i ++){
this.addEmptyRow();

}
随机rnd = new Random(); (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);
返回键;
}

@Override
public boolean isCellEditable(int row,int col){
System.out.println(isCellEditable row+ row +col + col);
if(col == 1){
System.out.println(TRUE);
返回true;
}
返回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()。
}

@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&扩展对象> 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(); (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<?扩展对象> 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>(); (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<?扩展对象> targetColClass = this.getColumnClass(i);
对象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,I​​nterger,Double,Boolean,Double,String,Boolean,Date
m.getColumn ).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);
}
}


Update

Confirmed as a bug on JTable can't format given Object as Number when columnClass is Double (bug ID: 7051636). Feel free to vote for it, or if if you have an alternate (better) work-around, post it as a comment to the report.


I'm building a JTable with a custom table model built extending AbstractTableModel. My model need to support empty row to be displayed and sorted. So I follwed this post to implement that, and now works pretty fine.

I still have a problem whith formatted field in a JTable. Suppose I have the following model:

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();

    }
}

Everything works fine. But if I have a Double instead of an Integer:

public class MyModel extends AbstractTableModel{

        public Object[] types= {new Double(0.0), ""};
  .......

I'll get an Illegal Argument exception:

EDIT: new stack trace output after @Aaron Digulla suggestion

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Cannot format given Object as a Number at java.text.DecimalFormat.format(DecimalFormat.java:487) at java.text.Format.format(Format.java:140) at javax.swing.JTable$DoubleRenderer.setValue(JTable.java:5352) at javax.swing.table.DefaultTableCellRenderer.getTableCellRendererComponent(DefaultTableCellRenderer.java:237) at javax.swing.JTable.prepareRenderer(JTable.java:5720) at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2072) at javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:1974) at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1770) at javax.swing.plaf.ComponentUI.update(ComponentUI.java:143) at javax.swing.JComponent.paintComponent(JComponent.java:752) at javax.swing.JComponent.paint(JComponent.java:1029) at javax.swing.JComponent.paintChildren(JComponent.java:862) at javax.swing.JComponent.paint(JComponent.java:1038) at javax.swing.JViewport.paint(JViewport.java:747) at javax.swing.JComponent.paintChildren(JComponent.java:862) at javax.swing.JComponent.paint(JComponent.java:1038) at javax.swing.JComponent.paintChildren(JComponent.java:862) at javax.swing.JComponent.paint(JComponent.java:1038) at javax.swing.JComponent.paintChildren(JComponent.java:862) at javax.swing.JComponent.paint(JComponent.java:1038) at javax.swing.JLayeredPane.paint(JLayeredPane.java:567) at javax.swing.JComponent.paintChildren(JComponent.java:862) at javax.swing.JComponent.paintToOffscreen(JComponent.java:5131) at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:278) at javax.swing.RepaintManager.paint(RepaintManager.java:1224) at javax.swing.JComponent.paint(JComponent.java:1015) at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:21) at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:60) at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:97) at java.awt.Container.paint(Container.java:1780) at java.awt.Window.paint(Window.java:3375) at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:796) at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:713) at javax.swing.RepaintManager.seqPaintDirtyRegions(RepaintManager.java:693) at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:125) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) at java.awt.EventQueue.dispatchEvent(EventQueue.java:597) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

Why this?

getValueAt returns always the same value to fill all tables entries with it. This is only for debug :

@Override
    public Object getValueAt(int rowIndex, int columnIndex) {
         return this.EMPTY_ROW;
    }

For example if i change to :

 @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
    }

all works fine even if some field of the table are String. It suggest to me that because an Integer and a Double can be transformed into String, this won't cause problem. Anyway I would like to understand why a generic Object like my EMPTY_ROW can be accepted as value of a declared Integer field while this don't work with Double fields.

EDIT2:

If I remove getClass method in my table model. It works. Anyway I would like to solve this without having to remove that method, even if this will force me to implement some custom render methods.

EDIT3:

here's an SSCCE. There is some errors while adding new values to the table, but hasn't nothing to do with rendering problems.

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();
    }

}

If you try to change

Class[] types = {Integer.class, String.class}; 

with :

Class[] types = {Double.class, String.class};

you can see the problem.

解决方案

how did Walter Laan says in his thread

Never give up! Never surrender!

EDIT: I can't resist, but due to my poor English I dare not to commenting why, where and how is that possible, nor works correctly, for confirmations I added Rob's two (little bit) modified class for TableColumnRendering ...,

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);
    }
}

这篇关于JTable中的问题格式化字段 - Integer和Double之间的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆