Java - JTable - getSelectedRow() 中的错误数据
Java - JTable - Wrong data in getSelectedRow()
我到处搜索所以这是我的'last'希望。
我有一个 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.run(RepaintManager.java:824)
at javax.swing.RepaintManager.run(RepaintManager.java:807)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.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.access00(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.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:709)
at java.awt.EventQueue.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.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)
非常感谢你们!
您错误地使用了 view-index 来索引模型。您的代码中的问题:
- 您的内部
for
循环应如下所示:
int rowModelId = convertRowIndexToModel( row );
for (int c = 0; c < headerCols.size(); c++) {
newRow.put(
headerCols.get(c),
(String) tableModel.getValueAt(rowModelId, c)
);
}
- 删除行应该这样完成:
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 介绍中了解有关 view-indexes 与 model-indexes 的更多信息。一些相关的引用:
The JTable uses integers exclusively to refer to both the rows and the columns of the model that it displays. The JTable simply takes a tabular range of cells and uses getValueAt(int, int) to retrieve the values from the model during painting. It is important to remember that the column and row indexes returned by various JTable methods are in terms of the JTable (the view) and are not necessarily the same indexes used by the model.
By default, columns may be rearranged in the JTable so that the view's columns appear in a different order to the columns in the model. This does not affect the implementation of the model at all: when the columns are reordered, the JTable maintains the new order of the columns internally and converts its column indices before querying the model.
[...]The following shows how to convert coordinates from JTable to that of the underlying model:
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。该案例处理的是列而不是行的不正确索引,但问题具有可比性。
Javadoc是你的朋友!
All of JTables row based methods are in terms of the RowSorter, which is not necessarily the same as that of the underlying TableModel. For example, the selection is always in terms of JTable so that when using RowSorter you will need to convert using convertRowIndexToView or convertRowIndexToModel.
根据Java docjTable.getSelectedRow()
returns第一个选择的行索引。对于第一个循环,一切都很好。但是,一旦删除该行,其余行将在删除一行后获得新索引。因此,删除一行后剩余的行的行索引现在将不同。
未排序的调试报告是因为在您正在试验的选定行之间有一行未被选中。
我到处搜索所以这是我的'last'希望。
我有一个 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.run(RepaintManager.java:824)
at javax.swing.RepaintManager.run(RepaintManager.java:807)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.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.access00(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.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:709)
at java.awt.EventQueue.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.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)
非常感谢你们!
您错误地使用了 view-index 来索引模型。您的代码中的问题:
- 您的内部
for
循环应如下所示:
int rowModelId = convertRowIndexToModel( row );
for (int c = 0; c < headerCols.size(); c++) {
newRow.put(
headerCols.get(c),
(String) tableModel.getValueAt(rowModelId, c)
);
}
- 删除行应该这样完成:
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 介绍中了解有关 view-indexes 与 model-indexes 的更多信息。一些相关的引用:
The JTable uses integers exclusively to refer to both the rows and the columns of the model that it displays. The JTable simply takes a tabular range of cells and uses getValueAt(int, int) to retrieve the values from the model during painting. It is important to remember that the column and row indexes returned by various JTable methods are in terms of the JTable (the view) and are not necessarily the same indexes used by the model.
By default, columns may be rearranged in the JTable so that the view's columns appear in a different order to the columns in the model. This does not affect the implementation of the model at all: when the columns are reordered, the JTable maintains the new order of the columns internally and converts its column indices before querying the model.
[...]The following shows how to convert coordinates from JTable to that of the underlying model:
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。该案例处理的是列而不是行的不正确索引,但问题具有可比性。
Javadoc是你的朋友!
All of JTables row based methods are in terms of the RowSorter, which is not necessarily the same as that of the underlying TableModel. For example, the selection is always in terms of JTable so that when using RowSorter you will need to convert using convertRowIndexToView or convertRowIndexToModel.
根据Java docjTable.getSelectedRow()
returns第一个选择的行索引。对于第一个循环,一切都很好。但是,一旦删除该行,其余行将在删除一行后获得新索引。因此,删除一行后剩余的行的行索引现在将不同。
未排序的调试报告是因为在您正在试验的选定行之间有一行未被选中。