Имеется задача, построить таблицу, столбцы которой являются полями в классе 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 ) переносятся непонятным образом.
Собственно почему так и как исправить?
Ответ
Дело в том, что когда вы перемещаете столбцы, они реально меняются местами в списке столбцов 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 List
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 ), которые делают то же самое.
Комментариев нет:
Отправить комментарий