JTable问题 – 删除筛选后的表格

huangapple go评论81阅读模式
英文:

JTable problem - deleting a filtered table

问题

以下是您提供的Java代码的翻译:

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.");
            }          
        });
    }
    
    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")
    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.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(4, 4, 4)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 312, Short.MAX_VALUE)
                .addContainerGap())
        );

        pack();
    }

    public static void main(String args[]) {
        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, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(ProblemGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(ProblemGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new ProblemGUI().setVisible(true);
            }
        });
    }

    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextField jTextField1;
}
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[] permissions = 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 permissions[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 removeProduct(int row){
        System.out.println("TableModel:removeProduct 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 row, int col) {
        if(isSelected){
            setForeground(table.getSelectionForeground());
            setBackground(table.getSelectionBackground());
        }else{
            setForeground(table.getForeground());
            setBackground(table.getBackground());
        }
       

<details>
<summary>英文:</summary>

I am doing a project in Java and use a jTable with a column with Buttons to delete the row. This work well. After that i added a textfield to filter the tablet and work too. The problema was when i try to use the 2 things. I search for a row and only display that row, Next i click on delete Button in that row, the programa delete the wrong row and give a error. Can someone show my a example how can do that? Sorry for my poor english.

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(&quot;(?i)&quot; + text));
}
}
@Override
public void removeUpdate(DocumentEvent e) {
String text = jTextField1.getText();
if(text.trim().length() == 0){
tr.setRowFilter(null);
}else{
tr.setRowFilter(RowFilter.regexFilter(&quot;(?i)&quot; + text));
}
}
@Override
public void changedUpdate(DocumentEvent de) {
throw new UnsupportedOperationException(&quot;Not supported yet.&quot;); //To change body of generated methods, choose Tools | Templates.
}          
});
}
private void initTable(){
products = new ArrayList();
products.add(new Product(1, &quot;Product 1&quot;));
products.add(new Product(2, &quot;Product 2&quot;));
products.add(new Product(3, &quot;Product 3&quot;));
model = new TableModel(products);
table = new JTable(model);
tr = new TableRowSorter&lt;&gt;(model);
table.setRowSorter(tr);
table.getColumn(&quot;Remove&quot;).setCellRenderer(new ButtonRenderer());
table.getColumn(&quot;Remove&quot;).setCellEditor(new ButtonEditor(new JCheckBox(), tr));
jScrollPane1.setViewportView(table);
}
@SuppressWarnings(&quot;unchecked&quot;)
// &lt;editor-fold defaultstate=&quot;collapsed&quot; desc=&quot;Generated Code&quot;&gt;                          
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.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(4, 4, 4)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 312, Short.MAX_VALUE)
.addContainerGap())
);
pack();
}// &lt;/editor-fold&gt;                        
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//&lt;editor-fold defaultstate=&quot;collapsed&quot; desc=&quot; Look and feel setting code (optional) &quot;&gt;
/* 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 (&quot;Nimbus&quot;.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, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(ProblemGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(ProblemGUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//&lt;/editor-fold&gt;
/* 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[]{&quot;Cod&quot;, &quot;Name&quot;, &quot;Remove&quot;};
private static final boolean[] permitions = new boolean[]{false, false, true};
private ArrayList&lt;Product&gt; products;
public TableModel(ArrayList&lt;Product&gt; 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(&quot;TableModel:removeProduto Row-&gt;&quot; + 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 row, int col) {
if(isSelected){
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
}else{
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setText((o == null) ? &quot;&quot; : o.toString());
return this;
}  

}


package problem;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.table.TableRowSorter;

public class ButtonEditor extends DefaultCellEditor{
protected JButton button;
private String label;
private boolean isPushed;
private int row;
private JTable table;
private TableRowSorter<TableModel> tr;

public ButtonEditor(JCheckBox jcb, TableRowSorter&lt;TableModel&gt; tr) {
super(jcb);
this.tr = tr;
button = new JButton();
button.setOpaque(true);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae) {
fireEditingStopped();
}   
});
}  
public Component getTableCellEditorComponent(JTable table, Object o, boolean isSelected, int row, int col){
if(isSelected){
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
}else{
button.setForeground(table.getForeground());
button.setBackground(table.getBackground());
}
label = (o == null) ? &quot;&quot; : o.toString();
button.setText(label);
isPushed = true;
this.row = row;
this.table = table;
return button;
}
public Object getCellEditorValue(){
if(isPushed){
System.out.println(&quot;Row: &quot; + row);
System.out.println(&quot;Convert Row: &quot; + table.convertRowIndexToModel(row));
((TableModel) table.getModel()).removeProduto(table.convertRowIndexToModel(row));
JOptionPane.showMessageDialog(button, &quot;Produto removido.&quot;);
}
isPushed = false;
return label;
}
public boolean stopCellEditing(){
isPushed = false;
return super.stopCellEditing();
}
protected void fireEditingStopped(){
System.out.println(&quot;FIRE EDITING STOPPED START&quot;);
super.fireEditingStopped();
}

}


[Inface Image][1]
[Error Image][2]
[1]: https://i.stack.imgur.com/orZy2.jpg
[2]: https://i.stack.imgur.com/uCYpP.jpg
</details>
# 答案1
**得分**: 2
问题出在我尝试使用这两个功能时。我搜索一行并且仅显示那一行。接下来,我点击该行中的删除按钮,程序却删除了错误的行。
你需要理解“模型”和“视图”的区别。
模型中的数据并没有被筛选。
只有筛选后的数据才会在视图中显示。
因此,模型中可能有20行数据,但在视图中只显示3行数据。
因此,模型和视图之间的行索引可能是不同的。
要从模型中删除一行,你需要将视图中的索引转换为模型中的索引,类似于:
```java
int modelRow = table.convertRowIndexToModel(table.getSelectedRow());
model.removeRow(modelRow);

请注意,当进行排序时,相同的逻辑也适用。模型中的数据并没有排序,视图中显示的数据是按排序顺序显示的,因此索引也需要进行转换。

编辑:

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

参见:Table Button Column,这是一个可重用的实现,允许你只需指定要在选定行上调用的操作。请注意,你仍然需要将索引转换为模型索引。

英文:

> The problema was when i try to use the 2 things. I search for a row and only display that row, Next i click on delete Button in that row, the programa delete the wrong row

You need to understand the difference between the "model" and the "view".

The data in the model is NOT filtered.

Only the filtered data is displayed in the view.

So you may have 20 rows of data in the model, but only 3 rows of data in the view.

Therefore the row index between the model and view may be different.

To delete a row from the model you need to convert the index from the view to the model using something like:

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

Note, the same logic applies when sorting. The data in the model is NOT sorted, the data in the view is displayed in a sorted order so the index will need to be converted as well.

Edit:

> i think the problem is the buttons inside the jTable.

See: Table Button Coumn for a reusable implementation that allows you to just specify an Action to invoke on the selected row. Note, you will still need to convert the index to the model index.

huangapple
  • 本文由 发表于 2020年9月24日 22:47:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/64048942.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定