JobClass에서 열로 지정된 객체를 숫자로 지정할 수없는 버그로 확인되었습니다. Double (버그 ID : 7051636) 입니다. 이에 대해 투표하거나 대안 (더 나은) 해결 방법이있는 경우 의견을 보고서에 게시하십시오.
<시간>확장 된 AbstractTableModel을 빌드 한 커스텀 테이블 모델로 JTable을 만들고 있습니다. 모델에서 빈 행을 표시하고 정렬하려면 지원해야합니다. 그래서 나는 이것을 구현하기 위해 포스트 를 작성했습니다. 꽤 잘 작동합니다.
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이있는 경우 :
public class MyModel extends AbstractTableModel{
public Object[] types= {new Double(0.0), ""};
.......
잘못된 인수 예외가 발생합니다 :
수정 : @Aaron Digulla 제안 후 새 스택 추적 출력
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)
이 이유는 무엇인가요?
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와 같은 일반 객체가 선언 된 정수 필드의 값으로 허용 될 수있는 이유를 이해하고 싶습니다.
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};
with :
Class[] types = {Double.class, String.class};
문제를 볼 수 있습니다.
- 답변 # 1
- 답변 # 2
정말 문제는 이전 토론과 관련이 없으며, 일반 바닐라가 있습니다 (내 영어 실력을 비교하십시오). 실제로 버그라고 생각합니까, 아니면 ViceVersaView를 보여 주면 누군가가 가능할 수 있습니다 영어로 된 JTable + TableModel + Comparator (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); } }
- 답변 # 3
문제는 이중이 아니라 다른 것입니다. 스택 추적에서 볼 수 있듯이 테이블은 이중 값 (
javax.swing.JTable$DoubleRenderer
)을 특별히 지원합니다. ).값이
setValue()
에 전달 된 문제Double
가 아닙니다 그러나 다른 것입니다. - 답변 # 4
문제는 : Double 값의 형식을 지정하면 문자열이되고, 열이 Double.class 만 허용하므로 되돌릴 수 없습니다. 따라서 Double.class를 String.class로 변경하면 작동합니다.
- Swing Java에서 JTable 행에 버튼을 추가하는 방법
- java : JTable 및 JScrollPane이 표시되지 않음
- java : JTable에 동적으로 열 추가
- java : JTable + Next /Previous 버튼에 표시된 행 제한
- jTable 내에서 체크 박스의 값을 얻고 Java에서 평균을 계산하는 방법
- java : 이동 후 마우스 커서 위치가 변경되지 않음
- java : 데이터베이스에서 날짜를 검색하고 캘린더로 변환하려면 어떻게해야합니까?
- java : 문자열을 메모리에로드하지 않고 JTextArea에서 텍스트 출력
- java : JPanel getpreferredsize ()는 JFrame에서 테두리를 뺀 크기 대신 10을 반환합니다.
- java : JScrollPane에서 가로 및 세로 스크롤바를 모두 스크롤 할 때 paintComponent가 호출되지 않습니다.
Walter Laan
어떻게 그의 실에서 말한다편집 : 저항 할 수는 없지만 내 영어 실력이 떨어지기 때문에 TableColumnRendering에 대해 Rob의 두 가지 (작은 비트) 수정 클래스를 추가 한 이유, 장소 및 방법이 가능하고 올바르게 작동하는지 언급하지 않습니다. ..,