#java #swing #jtable
Имеется задача, построить таблицу, столбцы которой являются полями в классе CustomItem. package com.kolos.Table; import java.util.Date; public class CustomItem { public Integer id; public String name; public Date date; public CustomItem(Integer id, String name, Date date) { this.id = id; this.name = name; this.date = date; } } Класс CustomColumnModel: package com.kolos.Table; import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.TableColumn; import java.lang.reflect.Field; public class CustomColumnModel extends DefaultTableColumnModel{ public CustomColumnModel(Class tClass) { for (Field tField : tClass.getDeclaredFields()){ TableColumn tColumn = new TableColumn(); tColumn.setHeaderValue(tField.getName()); tColumn.setModelIndex(getColumnCount()); tColumn.setIdentifier(tField); tField.setAccessible(true); this.addColumn(tColumn); } } } Модель таблицы: package com.kolos.Table; import javax.swing.table.AbstractTableModel; import java.lang.reflect.Field; import java.util.Date; public class CustomDataModel extends AbstractTableModel{ private CustomColumnModel columnModel; private CustomItem[] dataList = new CustomItem[3]; public CustomDataModel(CustomColumnModel columnModel) { this.dataList = new CustomItem[3]; this.dataList[0] = new CustomItem(1, "Fist", new Date()); this.dataList[1] = new CustomItem(2, "Second", new Date()); this.dataList[2] = new CustomItem(3, "Third", new Date()); this.columnModel = columnModel; } @Override public int getRowCount() { return this.dataList.length; } @Override public int getColumnCount() { return this.columnModel.getColumnCount(); } @Override public Object getValueAt(int rowIndex, int columnIndex) { try { Field tField = ((Field) columnModel.getColumn(columnIndex).getIdentifier()); return tField.get(dataList[rowIndex]); } catch (IllegalAccessException e) { return "IllegalAccessExeption"; } } } Класс CustomTable: package com.kolos.Table; import javax.swing.*; public class CustomTable extends JTable{ private CustomDataModel dataModel; private CustomColumnModel columnModel; public CustomTable() { setAutoCreateColumnsFromModel(false); columnModel = new CustomColumnModel(CustomItem.class); setColumnModel(columnModel); dataModel = new CustomDataModel(columnModel); setModel(dataModel); } } Фрейм: package com.kolos; import com.kolos.Table.CustomTable; import javax.swing.*; import java.awt.*; public class MainFrame extends JFrame{ public MainFrame() { this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.setSize(new Dimension(800, 600)); this.setLayout(new GridBagLayout()); //create table JScrollPane scrollPane = new JScrollPane(); CustomTable table = new CustomTable(); scrollPane.setViewportView(table); this.add(scrollPane, new GridBagConstraints( 0, 0, 1, 1, 1, 1, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0 )); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { MainFrame mainFrame = new MainFrame(); mainFrame.setVisible(true); } }); } } Проблема в том что при перетаскивании столбцов (например 2 -> 0) заголовки переносятся, а значения из модели (получаемые методом getValueAt ) переносятся непонятным образом. Собственно почему так и как исправить?
Ответы
Ответ 1
Дело в том, что когда вы перемещаете столбцы, они реально меняются местами в списке столбцов ColumnModel, при этом в TableModel.getValueAt координаты ячейки приходят уже пересчитанными в пространство модели (значение поля TableColumn.modelIndex) Поэтому когда вы ставите третью колонку на место первой, для показа первой колонки вызывается getValueAt( rowIndex, 2 ), вы берете у модели столбцов колонку по индексу 2, но туда уже сдвинулась средняя колонка, которая отвечала за вывод имени. Мне кажется, лучше всего держать получение данных по номеру столбца прямо в модели таблицы. Заведите список Field для доступа к данным, заполните его в конструкторе модели, как вы сейчас делаете в CustomColumnModel, и возвращайте имя колонки в TableModel.getColumnName(int). А TableColumnModel вообще не трогать. public class CustomDataModel extends AbstractTableModel { private CustomItem[] dataList = new CustomItem[3]; private Listfields = new ArrayList<>(); public CustomDataModel( Class tClass ) { this.dataList = new CustomItem[3]; this.dataList[0] = new CustomItem(1, "Fist", new Date()); this.dataList[1] = new CustomItem(2, "Second", new Date()); this.dataList[2] = new CustomItem(3, "Third", new Date()); for (Field tField : tClass.getDeclaredFields()){ tField.setAccessible(true); fields.add( tField ); } } @Override public int getRowCount() { return this.dataList.length; } @Override public int getColumnCount() { return this.fields.size(); } @Override public String getColumnName( int column ) { return fields.get( column ).getName(); } // можно возвращать тип столбца, тогда JTable будет выбирать соотв. TableCellRenderer // @Override // public Class getColumnClass( int column ) { // return fields.get( column ).getType(); // } @Override public Object getValueAt(int rowIndex, int columnIndex) { try { Field tField = fields.get( columnIndex ); return tField.get(dataList[rowIndex]); } catch (IllegalAccessException e) { return "IllegalAccessExeption"; } } } public class CustomTable extends JTable{ private CustomDataModel dataModel; public CustomTable() { setAutoCreateColumnsFromModel( true ); // не забудьте вернуть автосоздание dataModel = new CustomDataModel( CustomItem.class ); setModel( dataModel ); } } Либо вы можете в getValueAt искать нужную колонку по совпадению columnIndex и tableColumn.getModelIndex(), или воспользоваться методами jTable.convertColumnIndexToView( columnIndex ) (но нужно держать в модели ссылку на таблицу), или sun.swing.SwingUtilities2.convertColumnIndexToView( columnModel, columnIndex ), которые делают то же самое.
Комментариев нет:
Отправить комментарий