Java - JTable - getSelectedRow()中的数据错误

时间:2016-01-25 16:44:51

标签: java swing jtable

我到处搜索所以这是我的最后一次'希望。

我有一个JTable,我填充了一些CSV值。当我执行删除所选行的操作时,它不会删除所有行...要更好地理解调试:

Begin (total selected): 6
Removed index: 6
Removed index: 4
Removed index: 3
Removed index: 2
Removed index: 1
End (total selected): 0

但剩下一个......请注意,其中5个被删除了,但有一个被删除了......我不明白为什么会发生这种情况。

我的代码:

    // I got a List<LikedHashMap<String, String>> data
    // where I store my CSV data.
    // To populate the JTable I remove from this list (data)
    // and insert to JTable.
    // Before remove from JTable, I put back the row into data.
    // THIS LOOP IS WORKING PRETTY WELL.
    for (int row : this.table.getSelectedRows()) {

        // Vamos recolocar esta linha na lista de não selecionados
        LinkedHashMap<String, String> newRow = new LinkedHashMap<>();

        // Vamos pegar todos os dados da linha
        for (int c = 0; c < this.headerCols.size(); c++) {
            newRow.put(
                this.headerCols.get(c),
                (String) this.tableModel.getValueAt(row, c)
            );
        }

        // Adiciona aos nao selecionados
        if (!this.data.contains(newRow)) {
            this.data.add(newRow);
        }
    }

    /**
     * MY PROBLEM ACTUALLY BEGINS HERE...
     */

    System.out.println("Begin (total selected): "+String.valueOf(this.table.getSelectedRowCount()));

    // Remove da tabela.
    while(this.table.getSelectedRow() != -1) {

        System.out.println("Removed item: "+String.valueOf(this.table.getSelectedRowCount()));

        this.tableModel.removeRow(this.table.getSelectedRow());
    }

    System.out.println("End (total selected): "+String.valueOf(this.table.getSelectedRowCount()));

异常

Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Invalid index
at javax.swing.DefaultRowSorter.convertRowIndexToModel(DefaultRowSorter.java:514)
at javax.swing.JTable.convertRowIndexToModel(JTable.java:2642)
at javax.swing.JTable.getValueAt(JTable.java:2717)
at javax.swing.JTable.prepareRenderer(JTable.java:5706)
at javax.swing.plaf.synth.SynthTableUI.paintCell(SynthTableUI.java:683)
at javax.swing.plaf.synth.SynthTableUI.paintCells(SynthTableUI.java:580)
at javax.swing.plaf.synth.SynthTableUI.paint(SynthTableUI.java:364)
at javax.swing.plaf.synth.SynthTableUI.update(SynthTableUI.java:275)
at javax.swing.JComponent.paintComponent(JComponent.java:780)
at javax.swing.JComponent.paint(JComponent.java:1056)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5219)
at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:290)
at javax.swing.RepaintManager.paint(RepaintManager.java:1265)
at javax.swing.JComponent._paintImmediately(JComponent.java:5167)
at javax.swing.JComponent.paintImmediately(JComponent.java:4978)
at javax.swing.RepaintManager$4.run(RepaintManager.java:824)
at javax.swing.RepaintManager$4.run(RepaintManager.java:807)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:807)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:782)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:731)
at javax.swing.RepaintManager.access$1300(RepaintManager.java:64)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1720)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

非常感谢,伙计们!

3 个答案:

答案 0 :(得分:2)

您错误地使用视图索引来索引模型。代码中的问题:

  1. 您的内部for循环应如下所示:
  2. int rowModelId = convertRowIndexToModel( row );
    for (int c = 0; c < headerCols.size(); c++) {
        newRow.put(
            headerCols.get(c),
            (String) tableModel.getValueAt(rowModelId, c)
        );
    }
    
    1. 删除行应该像这样:
    2. while(table.getSelectedRow() != -1) {
          int rowModelId = convertRowIndexToModel( table.getSelectedRow() );
          System.out.println("Removed item: "+String.valueOf(this.table.getSelectedRowCount()));
          tableModel.removeRow(rowModelId);
      }
      

      您可以从顶部的Documentation on JTable介绍中了解有关视图索引与模型索引的更多信息。一些相关的引用:

        

      JTable仅使用整数来引用它显示的模型的行和列。 JTable只需要一个表格范围的单元格,并使用getValueAt(int,int)在绘制过程中从模型中检索值。 重要的是要记住,各种JTable方法返回的列和行索引都是JTable(视图),并不一定是模型使用的索引。

           

      默认情况下,可以在JTable中重新排列列,以便视图列的显示顺序与模型中的列不同。这根本不会影响模型的实现:当列重新排序时,JTable会在内部维护列的新顺序,并在查询模型之前转换其列索引。

           

      [...]以下显示如何将坐标从JTable转换为基础模型的坐标:

      int[] selection = table.getSelectedRows();
      for (int i = 0; i < selection.length; i++) {
        selection[i] = table.convertRowIndexToModel(selection[i]);
      }
      // selection is now in terms of the underlying TableModel
      

      前一段时间我对explains this difference between view and model回答了类似的问题。这种情况涉及对列而不是行进行不正确的索引,但问题具有可比性。

答案 1 :(得分:0)

Javadoc是你的朋友!

  

所有JTables基于行的方法都是根据RowSorter,它不一定与底层TableModel相同。例如,选择总是以JTable为基础,因此在使用RowSorter时,您需要使用convertRowIndexToView或convertRowIndexToModel进行转换。

答案 2 :(得分:0)

根据Java doc jTable.getSelectedRow()返回第一个选定的行索引。对于第一个循环,一切都很好。但是一旦删除了行,其余行将在删除一行后获得新索引。因此,对于删除一行后剩余的其余行,行索引现在将不同。

未经测试的调试报告是因为在您正在试验的所选行之间有一行未被选中。