JTable 中的格式化字段问题 - Integer 和 Double 之间的差异

发布于 2024-11-10 15:40:49 字数 14864 浏览 4 评论 0原文

##更新## 已确认为 JTable 上的错误,当 columnClass 为 Double 时,JTable 无法将给定对象格式化为数字(错误ID:7051636)。请随意投票,或者如果您有替代(更好)的解决方法,请将其作为报告的评论发布。


我正在构建一个 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), ""};
  .......

我会得到一个 Illegal Argument 异常:

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

线程“AWT-EventQueue-0”中出现异常 java.lang.IllegalArgumentException:无法将给定对象格式化为数字 在 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.ComponentUI.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(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.InitationEvent.dispatch(InitationEvent.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
    }

即使表的某些字段是字符串,所有工作都正常。这向我表明,因为 Integer 和 Double 可以转换为 String,这不会引起问题。 无论如何,我想了解为什么像我的 EMPTY_ROW 这样的通用对象可以被接受作为声明的 Integer 字段的值,而这不适用于 Double 字段。

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

进行更改,你就会看到问题。

##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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

没企图 2024-11-17 15:40:49

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

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);
    }
}
寒江雪… 2024-11-17 15:40:49

真正的问题是注意到与之前的辩论有关,有普通的香草(比较我缺少的英语技能),你认为这真的是错误吗,或者如果我展示了 ViceVersaView,也许有人可以评论 JTable + TableModel 的链+ 英语比较器(JTable API 的 TableRowSorter),eeeeeerghhh 在这种情况下真的是我的错

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

reall problem is noting to do with previous debate, there is plain vanilla (compare my missing English skills), are you think that that's really Bug, or if I showed ViceVersaView, maybe then somone can be able to comment that chains for JTable + TableModel + Comparator (TableRowSorter for JTable API) in English language, eeeeeerghhh really my bad in this case

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);
    }
}
黑寡妇 2024-11-17 15:40:49

问题不在于双重,而在于其他。正如您在堆栈跟踪中看到的,该表对双精度值有特殊支持 (javax.swing.JTable$DoubleRenderer)。

问题是传递给 setValue() 的值不是 Double 而是其他值。

The problem is not the double but something else. As you can see in the stack trace, the table has special support for double values (javax.swing.JTable$DoubleRenderer).

The problem us that the value passed to setValue() is not a Double but something else.

迷爱 2024-11-17 15:40:49

问题是:当您格式化 Double 值时,它会变成字符串,您无法将其返回,因为该列只允许 Double.class。因此,如果将 Double.class 更改为 String.class,它将起作用。

The thing is: when you format the Double value, it becomes a string, you can't return it back cause the column only allows Double.class. So if you change the Double.class to String.class, it will work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文