问题描述
我正在用Java做一个项目,并在jTable中使用带有Buttons的列来删除该行。这个工作很好。之后,我添加了一个文本字段来过滤平板电脑,并且也可以工作。问题是当我尝试使用2件事时。我搜索一行并仅显示该行,然后单击该行中的Delete按钮,程序将错误的行删除并给出错误。有人可以给我举个例子吗?对不起,我英语不好。
pod install --repo-update
package problem;
import java.util.ArrayList;
import javax.swing.JCheckBox;
import javax.swing.JTable;
import javax.swing.RowFilter;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.tablerowsorter;
public class ProblemGUI extends javax.swing.JFrame {
private TableModel model;
private ArrayList<Product> products;
private JTable table;
private tablerowsorter<TableModel> tr;
public ProblemGUI() {
initComponents();
initTable();
jTextField1.getDocument().addDocumentListener(new DocumentListener(){
@Override
public void insertUpdate(DocumentEvent e) {
String text = jTextField1.getText();
if(text.trim().length() == 0){
tr.setRowFilter(null);
}else{
tr.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
@Override
public void removeUpdate(DocumentEvent e) {
String text = jTextField1.getText();
if(text.trim().length() == 0){
tr.setRowFilter(null);
}else{
tr.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
@Override
public void changedUpdate(DocumentEvent de) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods,choose Tools | Templates.
}
});
}
private void initTable(){
products = new ArrayList();
products.add(new Product(1,"Product 1"));
products.add(new Product(2,"Product 2"));
products.add(new Product(3,"Product 3"));
model = new TableModel(products);
table = new JTable(model);
tr = new tablerowsorter<>(model);
table.setRowSorter(tr);
table.getColumn("Remove").setCellRenderer(new ButtonRenderer());
table.getColumn("Remove").setCellEditor(new ButtonEditor(new JCheckBox(),tr));
jScrollPane1.setViewportView(table);
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jTextField1 = new javax.swing.JTextField();
setDefaultCloSEOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1)
.addComponent(jTextField1,javax.swing.GroupLayout.DEFAULT_SIZE,517,Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jTextField1,javax.swing.GroupLayout.PREFERRED_SIZE,javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(4,4,4)
.addComponent(jScrollPane1,312,Short.MAX_VALUE)
.addContainerGap())
);
pack();
}// </editor-fold>
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available,stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(ProblemGUI.class.getName()).log(java.util.logging.Level.SEVERE,null,ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(ProblemGUI.class.getName()).log(java.util.logging.Level.SEVERE,ex);
} catch (illegalaccessexception ex) {
java.util.logging.Logger.getLogger(ProblemGUI.class.getName()).log(java.util.logging.Level.SEVERE,ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(ProblemGUI.class.getName()).log(java.util.logging.Level.SEVERE,ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokelater(new Runnable() {
public void run() {
new ProblemGUI().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextField jTextField1;
// End of variables declaration
}
package problem;
public class Product {
private int cod;
private String name;
private static final String remove = "Remover";
public Product(int cod,String name){
this.cod = cod;
this.name = name;
}
public int getCod(){ return cod; }
public void setCod(int cod){ this.cod = cod; }
public String getName(){ return name; }
public void setName(String name){ this.name = name; }
public String getRemove(){ return remove; }
}
package problem;
import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;
public class TableModel extends AbstractTableModel{
private static final int COL_COD = 0;
private static final int COL_NAME = 1;
private static final int COL_REMOVE = 2;
private static final String[] headers = new String[]{"Cod","Name","Remove"};
private static final boolean[] permitions = new boolean[]{false,false,true};
private ArrayList<Product> products;
public TableModel(ArrayList<Product> products){
this.products = products;
}
@Override
public int getRowCount() { return products.size(); }
@Override
public int getColumnCount() { return headers.length; }
@Override
public Object getValueAt(int row,int col) {
switch (col){
case COL_COD:
return products.get(row).getCod();
case COL_NAME:
return products.get(row).getName();
case COL_REMOVE:
return products.get(row).getRemove();
default:
break;
}
return null;
}
@Override
public String getColumnName(int index) { return headers[index]; }
@Override
public boolean isCellEditable(int row,int col) { return permitions[col]; }
@Override
public Class getColumnClass(int columnIndex) {
if(columnIndex == COL_COD) {
return Integer.class;
}
return String.class;
}
@Override
public void setValueAt(Object value,int row,int col){
switch (col) {
case COL_COD:
products.get(row).setCod((int) value);
break;
case COL_NAME:
products.get(row).setName(value.toString());
break;
default:
break;
}
}
public void removeProduto(int row){
System.out.println("TableModel:removeProduto Row->" + row);
products.remove(row);
fireTableRowsDeleted(row,row);
}
}
package problem;
import java.awt.Component;
import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
public class ButtonRenderer extends JButton implements TableCellRenderer{
public ButtonRenderer(){
setopaque(true);
}
@Override
public Component getTableCellRendererComponent(JTable table,Object o,boolean isSelected,boolean hasFocus,int col) {
if(isSelected){
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
}else{
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setText((o == null) ? "" : o.toString());
return this;
}
}
解决方法
问题在于当我尝试使用2种东西时。我搜索一行并仅显示该行,然后单击该行中的删除按钮,程序将错误的行删除
您需要了解“模型”和“视图”之间的区别。
模型中的数据未过滤。
视图中仅显示过滤的数据。
因此,您在模型中可能有20行数据,但视图中只有3行数据。
因此,模型和视图之间的行索引可能不同。
要从模型中删除一行,您需要使用以下方法将索引从视图转换为模型:
int modelRow = table.convertRowIndexToModel( table.getSelectedRow() );
model.removeRow( modelRow );
注意,排序时适用相同的逻辑。模型中的数据未排序,视图中的数据按排序顺序显示,因此索引也需要转换。
编辑:
我认为问题在于jTable中的按钮。
请参阅:Table Button Coumn,以获取可重用的实现,该实现允许您仅指定要在所选行上调用的Action。注意,您仍然需要将索引转换为模型索引。