简体   繁体   中英

remove a row from jtable with jbutton

I have a JTable with JButton like this. first pic

if I click the "+" button,the table is like this. second pic

then, if I click the "-" button on the second line, it's ok.

now the table has only one row which was added by the "+" button.

so the question is that, I clicked the "-" button on the row,it throws an exception below:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 1 >= 1
at java.util.Vector.elementAt(Vector.java:477)
at javax.swing.table.DefaultTableModel.setValueAt(DefaultTableModel.java:664)

what happened?

this is my code:

public class TableDeleteButtonEditor extends AbstractCellEditor implements TableCellEditor{

/**
 * 
 */
private static final long serialVersionUID = 1L;
JButton button;
String label;
boolean isPushed;
Vector<Vector<String>> vPartsTypeData;

DefaultTableModel dtm;
JTable partsTypeValueTable;

public TableDeleteButtonEditor(Vector<Vector<String>> vPartsTypeData, DefaultTableModel dtm, JTable partsTypeValueTable) {

    // TODO Auto-generated constructor stub
    //this.setClickCountToStart(1);
    this.vPartsTypeData = vPartsTypeData;
    this.dtm = dtm;
    this.partsTypeValueTable = partsTypeValueTable;
    this.vPartsTypeData = vPartsTypeData;
    button = new JButton();
    int selectedRow = partsTypeValueTable.getSelectedRow();
    System.out.println("selectedRow:"+selectedRow);
    System.out.println("Count:"+vPartsTypeData.size());
    button.addActionListener(new deleteButtonListener());
}

public Component getTableCellEditorComponent(final JTable table, Object value,  boolean isSelected,int row, int column) {
    if (isSelected) {
        button.setFont(new Font("Arial",Font.PLAIN,30));
        button.setForeground(table.getSelectionForeground());  
        button.setBackground(table.getSelectionBackground());  
    } else {
        button.setFont(new Font("Arial",Font.PLAIN,30));
        button.setForeground(table.getForeground());  
        button.setBackground(table.getBackground());  
    }  
    label = (value == null) ? "" : value.toString();  
    button.setText(label);
    isPushed = true;  
    return button;  
}  

public Object getCellEditorValue() {  
    if (isPushed) {

    }  
    isPushed = false;  
    return new String(label);  
}  

public boolean stopCellEditing() {  
    isPushed = false;
    return super.stopCellEditing();  
}  

public class deleteButtonListener implements ActionListener
{
    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        System.out.println("-----");
        int selectedRow = partsTypeValueTable.getSelectedRow();
        //System.out.println("selectedRow:"+selectedRow);
        //System.out.println("Count:"+vPartsTypeData.size());
        dtm.removeRow(selectedRow-1);

        //vPartsTypeData.remove(partsTypeValueTable.getSelectedRow());
        System.out.println("tableCount:"+partsTypeValueTable.getRowCount());
        //dtm.fireTableChanged(null);
        partsTypeValueTable.setModel(dtm);
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                partsTypeValueTable.repaint();
                partsTypeValueTable.validate();
                partsTypeValueTable.updateUI();
                dtm.fireTableDataChanged();
            }
            });

    }
}

}

So, a little bit of a look at the stack trace can lead us to a better understanding of what's going on...

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 1 >= 1
    at java.util.Vector.elementAt(Vector.java:477)
    at javax.swing.table.DefaultTableModel.setValueAt(DefaultTableModel.java:664)
    at javax.swing.JTable.setValueAt(JTable.java:2741)
    at javax.swing.JTable.editingStopped(JTable.java:4723)
    at javax.swing.AbstractCellEditor.fireEditingStopped(AbstractCellEditor.java:141)
    at javax.swing.AbstractCellEditor.stopCellEditing(AbstractCellEditor.java:85)

So, basically stopCellEditing is triggering a call to setValueAt , passing in the editing row , column and the result of getCellEditorValue , but, since this occurs AFTER the ActionListener has removed the row from the TableModel , it breaks, as the row, which setValueAt is trying to update simply no longer exists (or worse is a different row altogether).

It's not the responsibility of the TableCellEditor to modify the TableModel , instead, it should be reporting back to the TableModel a state value which it can use to make decisions about what it should do.

A simplified version of the editor might look something like...

public class TableDeleteButtonEditor extends AbstractCellEditor implements TableCellEditor {

    /**
     *
     */
    private static final long serialVersionUID = 1L;
    JButton button;
    boolean isPushed;

    public TableDeleteButtonEditor() {
        button = new JButton();
        button.addActionListener(new DeleteButtonListener());
    }

    public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, int row, int column) {
        if (isSelected) {
            button.setFont(new Font("Arial", Font.PLAIN, 30));
            button.setForeground(table.getSelectionForeground());
            button.setBackground(table.getSelectionBackground());
        } else {
            button.setFont(new Font("Arial", Font.PLAIN, 30));
            button.setForeground(table.getForeground());
            button.setBackground(table.getBackground());
        }
        button.setText((value == null) ? "" : value.toString());
        isPushed = false;
        return button;
    }

    public Object getCellEditorValue() {
        return isPushed;
    }

    public class DeleteButtonListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            isPushed = true;
            stopCellEditing();
        }
    }
}

The core functionality of the editor simply revolves around the state of the isPushed value.

The TableModel now needs to inspect this value when setValueAt is called and respond to it

@Override
public void setValueAt(Object aValue, int row, int column) {
    if (column == 0 && (aValue instanceof Boolean)) {
        boolean pushed = (boolean) aValue;
        if (pushed) {
            removeRow(row);
        }
    }
}                   

And viola, row is now deleted and everybody is happy.

Runnable example...

import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                DefaultTableModel model = new DefaultTableModel(new String[]{"A"}, 0) {
                    @Override
                    public void setValueAt(Object aValue, int row, int column) {
                        if (column == 0 && (aValue instanceof Boolean)) {
                            boolean pushed = (boolean) aValue;
                            if (pushed) {
                                removeRow(row);
                            }
                        }
                    }
                };
                model.addRow(new Object[]{"-"});
                model.addRow(new Object[]{"-"});
                JTable table = new JTable(model);
                TableColumn column = table.getColumnModel().getColumn(0);
                column.setCellEditor(new TableDeleteButtonEditor());

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new JScrollPane(table));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TableDeleteButtonEditor extends AbstractCellEditor implements TableCellEditor {

        /**
         *
         */
        private static final long serialVersionUID = 1L;
        JButton button;
        boolean isPushed;
        JTable partsTypeValueTable;

        public TableDeleteButtonEditor() {
            button = new JButton();
            button.addActionListener(new DeleteButtonListener());
        }

        public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, int row, int column) {
            partsTypeValueTable = table;
            if (isSelected) {
                button.setFont(new Font("Arial", Font.PLAIN, 30));
                button.setForeground(table.getSelectionForeground());
                button.setBackground(table.getSelectionBackground());
            } else {
                button.setFont(new Font("Arial", Font.PLAIN, 30));
                button.setForeground(table.getForeground());
                button.setBackground(table.getBackground());
            }
            button.setText((value == null) ? "" : value.toString());
            isPushed = false;
            return button;
        }

        public Object getCellEditorValue() {
            return isPushed;
        }

        public class DeleteButtonListener implements ActionListener {

            @Override
            public void actionPerformed(ActionEvent e) {
                isPushed = true;
                stopCellEditing();
            }
        }
    }
}

As I said, I don't like this approach, it's a personally thing, but as a user, I find it frustrating and much prefer something more like this for example .

However, you might like to also have a look at Table Button Column for another approach

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM