首页 > 解决方案 > 当列重新排列时,对 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

标签: javaswing

解决方案


switch语句执行匹配大小写之后的所有语句。这意味着,一旦满足条件,将执行 switch 块中的所有代码。这可以通过添加break;到每个案例中来避免。在您的示例中,当您设置模板时,您还设置了注释。

switch (column) {
    case 0:
        rei.setTemplate(value.toString());
        break;
    case 1:
        rei.setComment(value.toString());
        break;
   }

推荐阅读