方法fireTableStructureChanged()
从头开始重新绘制整个JTable。众所周知,用户指定的列宽和用户指定的行排序(当用户点击其中一个列的标题时)将丢失。
有没有办法存储自定义排序并在调用fireTableStructureChanged()
后将其检索回来?
可能是方法convertRowIndexToModel
和convertRowIndexToView
可以帮助......
或者是否有另一种方法可以重新绘制整个表(在更改行数后)并保持排序?
以下是我添加/删除某些行的实验的简短示例:
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.AbstractTableModel;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
public class Table extends JFrame {
private static final long serialVersionUID = 1L;
private JTable table;
private String[][] tableData = {{"a", "5"},
{"b", "4"},
{"c", "9"},
{"d", "2"},
{"e", "1"},
{"f", "7"},
{"g", "3"},
{"h", "8"},
{"i", "6"}};
private String[] columns = {"A", "B"};
public Table() {
MyTableModel mtm = new MyTableModel(tableData, columns);
this.setLayout(new BorderLayout());
table = new JTable(mtm);
table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.getTableHeader().setReorderingAllowed(false);
table.setCellSelectionEnabled(true);
table.setAutoCreateRowSorter(true);
JScrollPane scrollpane = new JScrollPane(table);
scrollpane.setPreferredSize(new Dimension(600, 150));
this.add(scrollpane);
this.setLocation(300, 100);
setVisible(true);
pack();
//Trying to add and remove some rows:
mtm.addRow(new Object[]{"new 1", "new 2"});
mtm.removeRow(2);
mtm.removeRow(3);
table.addNotify();
}
public class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private String[][] tableData;
private String[] columns;
public MyTableModel(String[][] tableData, String[] columns) {
this.tableData = tableData;
this.columns = columns;
}
public void addRow(Object newRow) {
fireTableRowsInserted(2, 2);
}
public void removeRow(int row) {
fireTableRowsDeleted(row, row);
}
public int getRowCount() {
return tableData.length;
}
public int getColumnCount() {
return columns.length;
}
public String getColumnName(int column) {
return columns[column];
}
public Object getValueAt(int row, int col) {
return tableData[row][col];
}
public void setValueAt(Object value, int row, int col) {
String oldValue = (String) tableData[row][col];
if(oldValue.equals((String)value)) {
return;
}
tableData[row][col] = value.toString();
}
public boolean isCellEditable(int row, int col) {
return true;
}
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Table();
}
});
}
}
答案 0 :(得分:2)
根据AbstractTableModel#fireTableStructureChanged() javadoc:
通知所有侦听器表的结构已更改。该 表中的列数,以及新的名称和类型 列可能与先前的状态不同。如果
JTable
接收此事件并设置其autoCreumnsColumnsFromModel标志 丢弃它拥有的任何表列并重新分配默认列 按照它们出现在模型中的顺序。这与呼叫相同setModel(TableModel)
上的JTable
。
因此,如果你调用这个方法然后没有意义保持列宽(因为可能已经改变),也没有行排序或过滤(也可能有数据更改)。
还是有另一种方法可以重新绘制整个表(在更改行数后)并保持排序吗?
如果要在插入/删除行上更新表数据,则需要在表模型中提供此类方法,并在此类事件中通知TableModelListener:
class MyTableModel extends AbstractTableModel {
...
public void addRow(Object newRow) {
// add row to underlying data structure here
fireTableRowsInserted(rowIndex, rowIndex);
}
public void remove(Object rowToBeDeleted) {
// remove row from the underlying data structure here
fireTableRowsDeleted(rowIndex, rowIndex);
}
...
}
请参阅AbstractTableModel API:
这样,列宽和行排序和过滤将保持不变。