проблема форматирования полей в JTable - различия между Integer и Double - PullRequest
5 голосов
/ 31 мая 2011

Обновление

Подтверждено как ошибка на JTable не может отформатировать данный объект как число, когда columnClass имеет значение Double (идентификатор ошибки: 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:

EDIT: вывод новой трассировки стека после предложения @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 (DefaultTableCellRenderesw.are.j.R.D.Rax.37.Rax.37.2)(JTable.java:5720) в javax.swing.plaf.basic.BasicTableUI.paintCell (BasicTableUI.java:2072) в javax.swing.plaf.basic.BasicTableUI.paintCells (BasicTableUI.java:1974) в javax.plaf.basic.BasicTableUI.paint (BasicTableUI.java:1770) в javax.swing.plaf.ComponentUI.update (ComponentUI.java:143) в javax.swing.JComponent.paintComponent (JComponent.java:752 at).JComponent.paint (JComponent.java:1029) в javax.swing.JComponent.paintChildren (JComponent.java:862) в javax.swing.JComponent.paint (JComponent.java:1038) в javax.swing.JViewport.paint (.java: 747) в javax.swing.JComponent.paintChildren (JComponent.java:862) в javax.swing.JComponent.paint (JComponent.java:1038) в javax.swing.JComponent.paintChildren (JCompon2).на javax.swing.JComponent.paint (JComponent.java:1038) на javax.swing.JComponent.paintChildren (JComponent.java:862) на javax.swing.JComponent.paint (JComponent.java:1038) на javax.jpg.JLayeredPane.paint (JLayeredPane.java:567) по адресу javax.swing.JComponent.paintChildren (JComponent.java:862) по адресу javax.swing.JComponent.paintToOffscreen (JComponent.java:5131) Пейджен.java: 278) на javax.swing.RepaintManager.paint (RepaintManager.java:1224) на javax.swing.JComponent.paint (JComponent.java:1015) на java.awt.GraphicsCallback $ PaintCallback.run (GraphicsCallback.jun)a: 21) в sun.awt.SunGraphicsCallback.runOneComponent (SunGraphicsCallback.java:60) в sun.awt.SunGraphicsCallback.runComponents (SunGraphicsCallback.java:97) в java.awt.Container.paint (Container.java:17)java.awt.Window.paint (Window.java:3375) в javax.swing.RepaintManager.paintDirtyRegions (RepaintManager.java:796) в javax.swing.RepaintManager.paintDirtyRegions (RepaintManager.java:713) в javaxswing.seqPaintDirtyRegions (RepaintManager.java:693) в javax.swing.SystemEventQueueUtilities $ ComponentWorkRequest.run (SystemEventQueueUtilities.java:125) в java.awt.event.InvocationEvent.dispatch (InvavaueE.t).dispatchEvent (EventQueue.java:597) по адресу java.awt.EventDispatchThread.pumpOneEventForFilters (EventDispatchThread.java:269) по адресу java.awt.EventDispatchThread.pumpEventsForFilter (EventDispatchThread.javaisatchHatchDatchPextHt: 174) в java.awt.EventDispatchThread.pumpEvents (EventDispatchThread.java:169)в java.awt.EventDispatchThread.pumpEvents (EventDispatchThread.java:161) at 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};

Вы можете увидеть проблему.

Ответы [ 4 ]

5 голосов
/ 31 мая 2011

как Walter Laan говорит в своей теме

Never give up! Never surrender!

РЕДАКТИРОВАТЬ: Я не могу сопротивляться, но из-за моего плохого английского я не осмеливаюсь комментировать, почему, где и как это возможно, и не работает правильно, для подтверждений я добавил два (немного) измененных класса Роба для 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);
    }
}
3 голосов
/ 07 июня 2011

Реальная проблема не в том, что связано с предыдущими дебатами, есть простая ваниль (сравните мои недостающие навыки английского), думаете ли вы, что это действительно ошибка, или если я показал ViceVersaView, возможно, тогда кто-то сможет прокомментировать эти цепочки дляJTable + TableModel + Comparator (TableRowSorter для JTable API) на английском языке, 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);
    }
}
2 голосов
/ 31 мая 2011

Проблема не в двойном, а в другом. Как видно из трассировки стека, в таблице есть специальная поддержка двойных значений (javax.swing.JTable$DoubleRenderer).

Проблема в том, что значение, переданное setValue(), это не Double, а что-то еще.

0 голосов
/ 15 октября 2014

Дело в том, что когда вы форматируете значение Double, оно становится строкой, вы не можете вернуть его обратно, поскольку в столбце допускается только Double.class.Так что если вы измените Double.class на String.class, он будет работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...