我试图创造一个简单的" JTable使用TableModel绑定到ArrayList以扩展AbstractTableModel。我的目标是保留所有内置的JTable功能,允许单元格编辑,行排序和列重新排列。我在这里提供的示例完成所有这些......但是......在一定的操作序列下,当编辑单元格然后通过拖动列标题重新排列表格列,或者使用列标题按钮对表格进行排序时,内容最近编辑的单元格被复制到表格行的两列中。
我可以按如下方式重现问题:运行示例。双击或按F2编辑左上角单元格的内容,然后按ENTER键。将左侧列标题向右拖动到其相对位置。行的两个单元格的值都会更改以匹配所选单元格。同样,编辑左上角的单元格,然后按ENTER键。然后单击任一列标题以对表进行排序。排序根据需要完成,但刚刚编辑的单元格的内容将复制到行的另一列。如果按TAB或ESC终止编辑,则行为略有不同。但问题仍然发生在"权利"行动顺序。
我认为这个问题与我的TableModel.getValueAt和.setValueAt方法需要在TableModel列索引和View列索引之间进行转换有关,但是,就我而言,我无法弄清楚如何或在哪里进行转换。
任何帮助都将不胜感激。
package tableexample;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
public final class TableExample extends JFrame {
public List<REItem> REList;
public JTable tblREList;
public TableExample() {
REList = new ArrayList<>();
REList.add(new REItem("Template1", "Comment1"));
REList.add(new REItem("Template2", "Comment2"));
RETableModel retm = new RETableModel(REList);
tblREList = new JTable(retm);
tblREList.setAutoCreateRowSorter(true);
JScrollPane spREList = new JScrollPane(tblREList);
this.add(spREList); //add the table to the frame
this.setTitle("Table Example");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setVisible(true);
} // end TableExample constructor
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
TableExample notUsed = new TableExample();
});
} //end main
/**
* One item for the RETable
*/
public final class REItem {
String template;
String comment;
public REItem(String tmp, String cmt) {
this.template = tmp;
this.comment = cmt;
}
public String getTemplate() { return template; }
public String getComment() { return comment; }
public void setTemplate(String value) { this.template = value; }
public void setComment(String value) { this.comment = value; }
} // end class REItem
public class RETableModel extends AbstractTableModel {
private List<REItem> reList = new ArrayList();
private final String[] columnNames = { "Template", "Comment" };
public RETableModel(List<REItem> list){
this.reList = list;
}
@Override
public String getColumnName(int column){
return columnNames[column];
}
@Override
public int getRowCount() {
return reList.size();
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public Object getValueAt(int rowIndex, int column) {
REItem rei = reList.get(rowIndex);
switch (column) {
case 0:
return rei.getTemplate();
case 1:
return rei.getComment();
}
return null; // default case
}
@Override
public boolean isCellEditable(int row, int column) {
return true;
}
@Override
public Class<?> getColumnClass(int column){
switch (column){
case 0:
return String.class;
case 1:
return String.class;
}
return null; // default case
}
@Override
public void setValueAt(Object value, int row, int column) {
REItem rei = reList.get(row);
switch (column) {
case 0:
rei.setTemplate(value.toString());
case 1:
rei.setComment(value.toString());
}
// uncommenting the below often causes IndexOutOfBoundsException: Invalid range exception
fireTableCellUpdated(row, column);
} // end setValueAt
} // end RETableModel
} // end class TableExample
答案 0 :(得分:3)
switch
语句执行匹配大小写后面的所有语句。这意味着,一旦满足条件,就会执行切换块中的所有代码。通过向每个案例添加break;
可以避免这种情况。在您的示例中,当您设置模板时,还可以设置注释。
switch (column) {
case 0:
rei.setTemplate(value.toString());
break;
case 1:
rei.setComment(value.toString());
break;
}
答案 1 :(得分:0)
这听起来像是Swing中的一个错误。示例代码中没有任何内容看起来错误。你的表模型没问题,如果你做错了什么就会出现在你的表中......你使用的是默认实现。
我能给出的唯一建议是尝试使用fireTableDataChanged()而不是fireTableCellUpdated(行,列)。没有尝试你的代码我认为你的数据可能很好(tablemodel的内容),但gui很困惑。
我没有发现其他人指出的setValueAt中缺少的中断。