简体   繁体   English

用jbutton从jtable中删除一行

[英]remove a row from jtable with jbutton

I have a JTable with JButton like this. 我有一个带有JButton这样的JTable。 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). 因此,基本上stopCellEditing会触发对setValueAt的调用,传入编辑rowcolumngetCellEditorValue的结果,但是由于这种情况在ActionListenerTableModel删除该行之后发生,因此该行中断了setValueAt是尝试更新根本就不存在了(或者更糟的是完全不同的行)。

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. 修改TableModel并不是TableCellEditor的责任,相反,它应该向TableModel报告一个状态值,可以使用该状态值来决定应该做什么。

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. 编辑器的核心功能只是围绕isPushed值的状态。

The TableModel now needs to inspect this value when setValueAt is called and respond to it 现在,在调用setValueAt时, TableModel需要检查该值并对其进行响应

@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 但是,您可能还想看看“ 表格按钮列”中的另一种方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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