在之前的一个问题(Convert modelRowIndex to viewRowIndex for sorted JTable)中,我表示我正试图创建一个简单的问题" JTable使用TableModel使用TableModel将ArrayList绑定到JTable。我的目标是 - 现在仍然是 - 保留java的所有内置JTable功能,允许进行单元格编辑,行排序和列重新排列。感谢您的帮助,该功能现在可以使用。
我现在正尝试添加插入和删除表格行的功能。我在这里提供的(更新的)示例有效...除了...在一定的操作序列下," IndexOutOfBoundsException"被扔了。这是我的代码:
package tableexample;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
public final class TableExample extends JFrame {
List<REItem> REList;
JTable tblREList;
JButton btnAddInsertRE, btnDeleteRE;
JScrollPane spMain;
JFrame frame;
Container pane;
public TableExample() {
// create and populate the ArrayList
REList = new ArrayList<>();
REList.add(new REItem("Template1", "Comment1"));
REList.add(new REItem("Template2", "Comment2"));
RETableModel retm = new RETableModel(REList); // Connect the List to the TableModel
// create GUI components
frame = new JFrame ("Table Example");
btnAddInsertRE = new JButton("Add/Insert");
btnDeleteRE = new JButton("Delete");
tblREList = new JTable(retm);
tblREList.setAutoCreateRowSorter(true);
spMain = new JScrollPane(tblREList);
// add button ActionListeners
btnAddInsertRE.addActionListener((ActionEvent evt) -> { btnAddInsertREActionPerformed(evt); });
btnDeleteRE.addActionListener((ActionEvent evt) -> { btnDeleteREActionPerformed(evt); });
// place GUI components and make the GUI visible
pane = frame.getContentPane();
pane.setLayout (null);
pane.add(btnAddInsertRE);
pane.add(btnDeleteRE);
pane.add(spMain);
btnAddInsertRE.setBounds (10, 10, 100, 25);
btnDeleteRE.setBounds (120, 10, 100, 25);
spMain.setBounds (10, 45, spMain.getPreferredSize().width, spMain.getPreferredSize().height);
frame.setSize(spMain.getWidth() + 40, spMain.getHeight() + 95);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
} // end TableExample constructor
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
TableExample notUsed = new TableExample();
});
} //end main
private void btnAddInsertREActionPerformed(ActionEvent evt) {
// Add a FileSelection object to the ArrayList
int r = tblREList.getSelectedRow(); // get row selection, if any
if (r < 0) { // no row selected
REList.add(new REItem("NewTemplate", "NewComment")); // append new item to end
r = REList.size()-1; // get index to new item
} else { // else no row selected
REList.add(r, new REItem("NewTemplate", "NewComment")); // insert above selected row
} // row selected or not
spMain.setViewportView(tblREList); // repaint the updated table
tblREList.getSelectionModel().setSelectionInterval(r, r); // select the new row
}
private void btnDeleteREActionPerformed(ActionEvent evt) {
int[] selRows = tblREList.getSelectedRows(); // see if any rows are selected
if (selRows.length>0) { // at least one row is selected
for (int r=selRows.length-1; r>=0; r--) { // delete each row, from the bottom up,
REList.remove(r); // so that indexes are correct and
} // don't change with each delete
tblREList.clearSelection(); // clear the row selection data
spMain.setViewportView(tblREList); // repaint the updated table
} else { // else no row(s) selected
JOptionPane.showMessageDialog(null, "Must select at least one item to delete");
} // no row selected
} // end btnDeleteREActionPerformed
public final class REItem {
String template;
String comment;
public REItem(String tmp, String cmt) {
this.template = tmp;
this.comment = cmt;
}
} // 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 row, int column) {
switch (column) {
case 0: return reList.get(row).template;
case 1: return reList.get(row).comment;
}
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) {
switch (column) {
case 0: reList.get(row).template = value.toString(); break;
case 1: reList.get(row).comment = value.toString(); break;
}
// uncommenting the below often causes IndexOutOfBoundsException: Invalid range exception
fireTableCellUpdated(row, column);
} // end setValueAt
} // end RETableModel
} // end class TableExample
问题可以重现如下:运行上面的例子,点击&#34;添加/插入&#34;按钮向表中追加一个新行,单击任一列标题重新排序表,然后单击&#34;删除&#34;按钮:&#34; IndexOutOfBoundsException&#34;被抛出,表明&#34;行&#34; TableModel的getValueAt方法指定的索引存在缺陷。
我认为这个问题与我的TableModel.getValueAt(也许是.setValueAt ???)方法需要在TableModel列索引和View列索引之间进行转换有关,但是对于我的生活,我可以& #39;弄清楚如何或在何处进行转换。此外,这个问题(Convert modelRowIndex to viewRowIndex for sorted JTable)表明需要在TableModel和View行索引之间进行转换,并且表重新排序必须在索引转换完成之前进行。
尽我所能,我无法弄清楚如何进行转换和/或如何确保在更新和重新排序表后进行转换。我需要听众吗?如果是这样,它应该是什么样的?
您能提供一些澄清和帮助吗?
答案 0 :(得分:0)
首先,变量名不应以大写字母开头。这是一个Java惯例,它与您发布的代码格式很混乱,使您的代码难以阅读。修复变量并遵循Java约定。
ArrayList只应用于最初向模型添加数据。
之后应该对TableModel进行更新,而不是对ArrayList进行更新。因此,您需要向TableModel添加方法,例如addREItem(...)
和removeREItem(...)
。
请参阅Row Table Model,了解如何为给定对象构建自定义TableModel的逐步示例,包括如何添加???(...)和删除???(。 ..)方法。
如果你想从表中删除选定的行,那么请查看:How to delete multiple rows from JTable , database at a time以获取一个工作示例,说明如何使用remove ???(...)方法完成此操作。