java - 当列重新排列时,对 JTable 列的编辑将数据放置在错误的列中
问题描述
我正在尝试创建一个“简单”的 JTable,它使用 TableModel 绑定到 ArrayList 以扩展 AbstractTableModel。我的目标是保留所有允许单元格编辑、行排序和列重新排列的内置 JTable 功能。我在这里提供的示例完成了所有这些......但是......在特定的操作序列下,当编辑单元格然后通过拖动列标题重新排列表格列或使用列标题按钮对表格进行排序时,最近编辑的单元格被复制到表格行的两列中。
我可以按如下方式重现该问题:运行示例。双击或按 F2 编辑左上角单元格的内容,然后按 ENTER。将左侧列标题向右拖动到其相反位置。行的两个单元格的值都会更改以匹配选定的单元格。同样,编辑左上角的单元格并按 ENTER。然后单击任一列标题对表格进行排序。排序按要求完成,但刚刚编辑的单元格的内容被复制到该行的另一列中。如果您按 TAB 或 ESC 终止编辑,则行为略有不同。但问题仍然发生在“正确”的行动顺序下。
我认为这个问题与我的 TableModel.getValueAt 和 .setValueAt 方法在 TableModel 列索引和 View 列索引之间转换的需要有关,但是,就我的一生而言,我无法弄清楚如何或在哪里进行转换。
任何帮助,将不胜感激。
包表示例;
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
解决方案
switch
语句执行匹配大小写之后的所有语句。这意味着,一旦满足条件,将执行 switch 块中的所有代码。这可以通过添加break;
到每个案例中来避免。在您的示例中,当您设置模板时,您还设置了注释。
switch (column) {
case 0:
rei.setTemplate(value.toString());
break;
case 1:
rei.setComment(value.toString());
break;
}
推荐阅读
- sql - SQLite:从一列中选择多个计数
- angular - 如何在订阅激活后将操作项添加到订阅中?
- c# - 开/关本金多层次
- sql - Oracle SQL 中的模式匹配
- freemarker - 如何在 FreeMarker 模板中调试低效的 JCR 查询?
- node.js - MSSQL - 节点 - 内存泄漏
- python - 如何在类主体中模拟外部模块调用和测试代码
- objective-c - 在objective-c中调用self.class上的方法实际上不是类方法时如何获得编译时失败?
- python - 加载文本文件时如何保持好行和坏行?
- flutter - Flutter - 将函数传递给 StatelessWidget 不起作用