#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 ), которые делают то же самое.
Комментариев нет:
Отправить комментарий