JTable问题-删除过滤的表

问题描述

我正在用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;
    }  
}

Inface Image Error Image

解决方法

问题在于当我尝试使用2种东西时。我搜索一行并仅显示该行,然后单击该行中的删除按钮,程序将错误的行删除

您需要了解“模型”和“视图”之间的区别。

模型中的数据未过滤。

视图中仅显示过滤的数据。

因此,您在模型中可能有20行数据,但视图中只有3行数据。

因此,模型和视图之间的行索引可能不同。

要从模型中删除一行,您需要使用以下方法将索引从视图转换为模型:

int modelRow = table.convertRowIndexToModel( table.getSelectedRow() );
model.removeRow( modelRow );

注意,排序时适用相同的逻辑。模型中的数据未排序,视图中的数据按排序顺序显示,因此索引也需要转换。

编辑:

我认为问题在于jTable中的按钮。

请参阅:Table Button Coumn,以获取可重用的实现,该实现允许您仅指定要在所选行上调用的Action。注意,您仍然需要将索引转换为模型索引。