我已经想出如何正确地对JTable进行排序,但我无法弄清楚如何在更改表格单元格时自动更新排序顺序.现在,我有这个(不可否认的很长)代码,主要基于
Java Tutorial的
How to Use Tables中的代码.我已经突出了我用// ADDED所做的更改.在这种情况下,新添加的值可以正确排序,但是当我进入编辑值时,即使我调用fireTableCellUpdated,它也似乎无法求助?
简而言之,当模型中的数据值发生变化时,如何让表格重新排序?
/*
* copyright (c) 1995 - 2008 Sun Microsystems,Inc. All rights reserved.
* See the standard BSD license.
*/
package components;
/*
* TableSortDemo.java requires no other files.
*/
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class TableSortDemo extends JPanel {
private boolean DEBUG = false;
public TableSortDemo() {
super();
setLayout(new BoxLayout(TableSortDemo.this,BoxLayout.PAGE_AXIS));
final MyTableModel m = new MyTableModel();
JTable table = new JTable(m);
table.setPreferredScrollableViewportSize(new Dimension(500,70));
table.setFillsViewportHeight(true);
table.setautocreateRowSorter(true);
//Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
//Add the scroll pane to this panel.
add(scrollPane);
// ADDED: button to add a value
JButton addButton = new JButton("Add a new value");
addButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
m.addValue(
JOptionPane.showInputDialog(
TableSortDemo.this,"Value?"));
}
});
// ADDED button to change a value
JButton setButton = new JButton("Change a value");
setButton.addActionListener(new ActionListener() {
/* (non-Javadoc)
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
m.setValueAt(
JOptionPane.showInputDialog(
TableSortDemo.this,"Value?"),Integer.parseInt(
JOptionPane.showInputDialog(
TableSortDemo.this,"Which?")),0);
}
});
add(addButton);
add(setButton);
}
class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = -7053335255134714625L;
private String[] columnNames = {"Column"};
// ADDED data as mutable ArrayList
private ArrayList<String> data = new ArrayList<String>();
public MyTableModel() {
data.add("Anders");
data.add("lars");
data.add("Betty");
data.add("Anna");
data.add("Jon");
data.add("Zach");
}
// ADDED
public void addValue(Object v) {
data.add(v.toString());
int row = data.size() - 1;
fireTableRowsInserted(row,row);
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.size();
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row,int col) {
return data.get(row) + " " + row;
}
/*
* JTable uses this method to determine the default renderer/
* editor for each cell. If we didn't implement this method,* then the last column would contain text ("true"/"false"),* rather than a check Box.
*/
public Class<String> getColumnClass(int c) {
return String.class;
}
/*
* Don't need to implement this method unless your table's
* editable.
*/
public boolean isCellEditable(int row,int col) {
//Note that the data/cell address is constant,//no matter where the cell appears onscreen.
if (col < 2) {
return false;
} else {
return true;
}
}
/*
* Don't need to implement this method unless your table's
* data can change.
*/
public void setValueAt(Object value,int row,int col) {
if (DEBUG) {
System.out.println("Setting value at " + row + "," + col
+ " to " + value
+ " (an instance of "
+ value.getClass() + ")");
}
data.set(row,value.toString());
// ADDED: uncommented this line,despite warnings to the contrary
fireTableCellUpdated(row,col);
if (DEBUG) {
System.out.println("New value of data:");
printDebugData();
}
}
private void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i=0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j=0; j < numCols; j++) {
System.out.print(" " + data.get(i));
}
System.out.println();
}
System.out.println("--------------------------");
}
}
/**
* Create the GUI and show it. For thread safety,* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("TableSortDemo");
frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
TableSortDemo newContentPane = new TableSortDemo();
newContentPane.setopaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokelater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
解决方法
这需要两个步骤:
首先,我通过使用this而不是autocreateRowSorter对数据更改进行了TableSorter排序:
sorter = new tablerowsorter<MyTableModel>(m); table.setRowSorter(sorter); sorter.setSortsOnUpdates(true);
然后,我不得不更改更新方法以更新整个表. fireTableCellUpdated和fireTableRowsUpdated只会重绘已更新的特定行,而不是整个表(这意味着你会看到一个重复出现的条目,它会在以后重新绘制后立即更改.所以,我改变了
fireTableCellUpdated(row,col);
至
fireTableRowsUpdated(0,data.size() - 1);
现在,即使数据发生变化,它也能正确排序,并保留选择.