简体   繁体   English

删除JTable的最后一行

[英]Removing last row of JTable

I'm kinda new on the scene and I was hoping you guys could help me... 我有点新奇,希望你们能帮助我...

I'm a beginner in java programming and I think Iwent over my head with this one. 我是Java编程的初学者,我认为我对此感到头疼。

My programms is working perfectly except for one little detail that annoys me. 除了让我烦恼的一个小细节,我的程序运行得很好。 I have a JTable with a button on the first column that allows to delete this row from the table. 我有一个JTable,它在第一列上带有一个按钮,允许从表中删除该行。 Its working well except when I try to delete the last row of the table, the button stay there and then the table freeze and i can't delete any rows because i receive a "Out of bound Exception" . 它工作正常,除了当我尝试删除表的最后一行时,按钮停留在那里,然后表冻结,并且由于我收到“ Out of bound Exception”,我无法删除任何行。 But, when I use the command table.getRowCount()); 但是,当我使用命令table.getRowCount());时。

Before and after the removal of the line, the table "knows" that a line was removed but as i said, the button stay there. 在删除该行之前和之后,该表“知道”该行已删除,但是正如我所说的,按钮停留在那里。 The screenshots in thumbnails show the situation before and after clicking the button next to the "Year" cell. 缩略图中的屏幕快照显示了单击“年份”单元格旁边的按钮之前和之后的情况。

之前后

It's good to add that i'm adding rows in the table from a button outside the table. 最好添加一下,我要通过表格外部的按钮在表格中添加行。

Heres my code: Main.java 这是我的代码:Main.java

static String [] title = {"X","Nom","SRM","Rend.","%","Kg",};
static Object[][] contenu;
static DefaultTableModel model1 = new DefaultTableModel(contenu, title);
static JTable tableauGrains = new JTable(model1);

tableauGrains.getColumn("X").setCellRenderer(new ButtonRenderer());
tableauGrains.getColumn("X").setCellEditor(new ButtonEditor(new JCheckBox()));

ButtonRenderer.java ButtonRenderer.java

import java.awt.Color;
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 Component getTableCellRendererComponent( JTable table, Object value,
                                                    boolean isSelected, boolean isFocus,
                                                    int row, int col) {
        Color beige = new Color(218, 217, 158);
        setBackground(beige);
        //On écrit dans le bouton ce que contient la cellule
        setText((value != null) ? value.toString() : "");
        //on retourne notre bouton
        return this;
    }
}

ButtonEditor.java ButtonEditor.java

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

import javax.swing.DefaultCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class ButtonEditor extends DefaultCellEditor {

    protected JButton button;
    private DeleteButtonListener bListener = new DeleteButtonListener();

    /**
     * Constructeur avec une checkBox
     * @param checkBox
     * @param count
     */
    @SuppressWarnings("deprecation")
    public ButtonEditor(JCheckBox checkBox) {
        //Par défaut, ce type d'objet travaille avec un JCheckBox
        super(checkBox);
        //On crée à nouveau notre bouton
        button = new JButton();
        button.setOpaque(true);
        //On lui attribue un listener
        button.addActionListener(bListener);

    }

      public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            //On précise le numéro de ligne à notre listener
            bListener.setRow(row);
            //Idem pour le numéro de colonne
              //On passe aussi le tableau en paramètre pour des actions potentielles
            bListener.setTable(table);

            //On réaffecte le libelle au bouton
            button.setText( (value == null) ? "" : value.toString() );
            //On renvoie le bouton
            return button;
          }

      class DeleteButtonListener implements ActionListener {

            private int row;
            private JTable table;

            public void setRow(int row){this.row = row;}
            public void setTable(JTable table){this.table = table;}

            public void actionPerformed(ActionEvent event) {
                if(table.getRowCount() > 0){
                //On affiche un message
                System.out.println("coucou du bouton: "+ ((JButton)event.getSource()).getText() );
                ((DefaultTableModel)table.getModel()).removeRow(this.row);
                    ((DefaultTableModel)table.getModel()).fireTableDataChanged();
                         }
          }
       }        
    }

I'm sorry about the french comments, its my native language. 我对法语评论感到抱歉,它是我的母语。

It's seems like the JTable is not "refreshing" itself after the removal of the last row. 似乎JTable在删除最后一行后并未“刷新”自身。

I'm I out of my league here ? 我不在这里吗?

Thank you very much and sorry about the long post, i tried to give you the most informations possible. 非常感谢您,对于冗长的帖子感到抱歉,我试图为您提供尽可能多的信息。

Djosimd EDIT: Djosimd编辑:

Execption pile after trying to click the 11th row after deleteing the row 12 : 删除第12行后,尝试单击第11行后的执行桩:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 11 >= 11 at java.util.Vector.elementAt(Unknown Source) at javax.swing.table.DefaultTableModel.setValueAt(Unknown Source) at javax.swing.JTable.setValueAt(Unknown Source) at javax.swing.JTable.editingStopped(Unknown Source) at javax.swing.AbstractCellEditor.fireEditingStopped(Unknown Source) at javax.swing.DefaultCellEditor$EditorDelegate.stopCellEditing(Unknown Source) at javax.swing.DefaultCellEditor.stopCellEditing(Unknown Source) at javax.swing.plaf.basic.BasicTableUI$Handler.mousePressed(Unknown Source) at java.awt.AWTEventMulticaster.mousePressed(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Com 线程“ AWT-EventQueue-0”中的异常java.lang.ArrayIndexOutOfBoundsException:11> = 11,位于javax.swing.table.DefaultTableModel.setValueAt(未知源)的java.util.Vector.elementAt(未知源) javax.swing.JTable.editingStopped(未知源)处的java.swing.AbstractCellEditor.fireEditingStopped(javax.swing.DefaultCellEditor $ EditorDelegate.stopCellEditing(未知源)处的.JTable.setValueAt(未知源) javax.swing.plaf.basic.BasicTableUI $ Handler.mousePressed的.DefaultCellEditor.stopCellEditing(未知源)java.awt.Component.processMouseEvent的java.awt.AWTEventMulticaster.mousePressed(未知源)处的Unknown Source(未知源)在javax.swing.JComponent.processMouseEvent(未知源)在java.awt.Component.processEvent(未知源)在java.awt.Container.processEvent(在java.awt.Component.dispatchEventImpl(未知源)在.awt.Container.dispatchEventImpl(未知源)在java.awt.Com ponent.dispatchEvent(Unknown Source) at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Window.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEventImpl(Unknown Source) at java.awt.EventQueue.access$200(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue$4.run(Unknown Source) at java.awt.EventQueue$4.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.do java.awt.LightweightDispatcher.remouseEvent(未知源)(java.awt.LightweightDispatcher.processMouseEvent(未知源)处java.awt.LightweightDispatcher.dispatchEvent(未知源)处java.awt.Container处的ponent.dispatchEvent(未知源)。 200美元的java.awt.Window.dispatchEventImpl(未知的来源)java.awt.EventQueue.dispatchEventImpl(未知的来源)的java.awt.EventQueue.access $ 200美元处的dispatchEventImpl(未知的来源) (未知源)在java.awt.EventQueue $ 3.run(未知源)在java.awt.EventQueue $ 3.run(在java.security.AccessController.doPrivileged(本机方法)在java.security.ProtectionDomain $ 1。 doIntersectionPrivilege(未知源)在java.security.ProtectionDomain $ 1.doIntersectionPrivilege(未知源)在java.awt.EventQueue $ 4.run(未知源)在java.awt.EventQueue $ 4.run(java.security.AccessController处) .doPrivileged(本地方法),位于java.security.ProtectionDomain $ 1.do IntersectionPrivilege(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source) java.awt.EventQueue.dispatchEvent上的IntersectionPrivilege(未知源)java.awt.EventDispatchThread.pumpOneEventForFilters(未知源)上java.awt.EventDispatchThread.pumpOneEventForFilters(未知源)处java.awt.EventDispatchThread.pumpEventsForFilter(未知源)处java.awt.EventDispatchThread.pumpEventsForHierarchy( java.awt.EventDispatchThread.pumpEvents(未知源)(java.awt.EventDispatchThread.pumpEvents(未知源)java.awt.EventDispatchThread.run(未知源)


SSCCE: SSCCE:

import java.awt.*;
import java.awt.event.*;
import javax.swing.table.*;
import javax.swing.*;

public class FooGui {
   static String[] title = { "X", "Nom", "SRM", "Rend.", "%", "Kg"};
   static Object[][] contenu;
   // !! static DefaultTableModel model1 = new DefaultTableModel(contenu, title);
   static DefaultTableModel model1 = new DefaultTableModel(title, 0);

   static JTable tableauGrains = new JTable(model1);

   public static void main(String[] args) {
      tableauGrains.getColumn("X").setCellRenderer(new ButtonRenderer());
      tableauGrains.getColumn("X").setCellEditor(new ButtonEditor(new JCheckBox()));

      for (int i = 0; i < 10; i++) {
         String btnText = "Btn " + (i + 1);
         Object[] rowData = {btnText, "", "", "", "", ""};
         model1.addRow(rowData);
      }
      JOptionPane.showMessageDialog(null, new JScrollPane(tableauGrains));
   }
}

class ButtonRenderer extends JButton implements TableCellRenderer {

   public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean isFocus, int row, int col) {
      Color beige = new Color(218, 217, 158);
      setBackground(beige);
      setText((value != null) ? value.toString() : "");
      return this;
   }
}

class ButtonEditor extends DefaultCellEditor {

   protected JButton button;
   private DeleteButtonListener bListener = new DeleteButtonListener();

   public ButtonEditor(JCheckBox checkBox) {
      super(checkBox);
      button = new JButton();
      button.setOpaque(true);
      button.addActionListener(bListener);
   }

   public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
      System.out.printf("row is: %d%n", row);
      bListener.setRow(row);
      bListener.setTable(table);

      // On réaffecte le libelle au bouton
      button.setText((value == null) ? "" : value.toString());
      // On renvoie le bouton
      return button;
   }

   class DeleteButtonListener implements ActionListener {

      private int row;
      private JTable table;

      public void setRow(int row) {
         this.row = row;
      }

      public void setTable(JTable table) {
         this.table = table;
      }

      public void actionPerformed(ActionEvent event) {
         if (table.getRowCount() > 0) {
            System.out.println("coucou du bouton: " + ((JButton) event.getSource()).getText());
            ((DefaultTableModel) table.getModel()).removeRow(this.row);
            stopCellEditing();  // !! not sure if this will help or not.
            //!!  ((DefaultTableModel) table.getModel()).fireTableDataChanged();
         }
      }
   }
}

As mentionned by camickr, you forget to stop the cell edition when removing your row, making it possible to continue "editing" the cell and trigger another removal of the row on a no longer existing row (hence the index out of bounds exception) 正如camickr所提到的,您忘记删除行时会忘记停止单元格版本,从而有可能继续“编辑”单元格并触发不再存在的行上的另一行删除(因此索引超出范围例外)

Simply cancel the edition of the button at the end. 只需在最后取消按钮的版本即可。 And as mentionned by camickr, no need to fireTableDataChanged() , removeRow() will take care of that. 正如camickr所提到的,不需要fireTableDataChanged()removeRow()会解决这一问题。

See SSCCE (not so short actually, but I am lazy to trim some lines) for demo: 参见SSCCE(实际上并不那么短,但是我懒于修剪一些行)以进行演示:

import java.awt.Color;
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.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class TestJTable {

    public class ButtonEditor extends DefaultCellEditor {

        protected JButton button;
        private final DeleteButtonListener bListener = new DeleteButtonListener();

        /**
         * Constructeur avec une checkBox
         * 
         * @param checkBox
         * @param count
         */
        @SuppressWarnings("deprecation")
        public ButtonEditor(JCheckBox checkBox) {
            // Par défaut, ce type d'objet travaille avec un JCheckBox
            super(checkBox);
            // On crée à nouveau notre bouton
            button = new JButton();
            button.setOpaque(true);
            // On lui attribue un listener
            button.addActionListener(bListener);

        }

        @Override
        public Component getTableCellEditorComponent(JTable table,
                Object value, boolean isSelected, int row, int column) {
            // On précise le numéro de ligne à notre listener
            bListener.setRow(row);
            // Idem pour le numéro de colonne
            // On passe aussi le tableau en paramètre pour des actions
            // potentielles
            bListener.setTable(table);

            // On réaffecte le libelle au bouton
            button.setText(value == null ? "" : value.toString());
            // On renvoie le bouton
            return button;
        }

        class DeleteButtonListener implements ActionListener {

            private int row;
            private JTable table;

            public void setRow(int row) {
                this.row = row;
            }

            public void setTable(JTable table) {
                this.table = table;
            }

            @Override
            public void actionPerformed(ActionEvent event) {
                if (table.getRowCount() > 0) {
                    // On affiche un message
                    System.out.println("coucou du bouton: "
                            + ((JButton) event.getSource()).getText());
                    ((DefaultTableModel) table.getModel()).removeRow(this.row);
                    ButtonEditor.this.cancelCellEditing();
                }
            }
        }
    }

    private static final String[] title = { "X", "Nom", "SRM", "Rend.", "%",
            "Kg", };

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestJTable().initUI();
            }
        });
    }

    protected void initUI() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        DefaultTableModel model = new DefaultTableModel(title, 4);
        JTable table = new JTable(model);
        table.getColumn("X").setCellEditor(new ButtonEditor(new JCheckBox()));
        table.getColumn("X").setCellRenderer(new ButtonRenderer());
        frame.add(new JScrollPane(table));
        frame.pack();
        frame.setVisible(true);
    }

    public static class ButtonRenderer extends JButton implements
            TableCellRenderer {

        private static final Color beige = new Color(218, 217, 158);

        @Override
        public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean isFocus, int row,
                int col) {
            setBackground(beige);
            // On écrit dans le bouton ce que contient la cellule
            setText(value != null ? value.toString() : "");
            // on retourne notre bouton
            return this;
        }
    }

}

Although this won't solve your problem, don't invoke fireTableDataChanged, that is the job of the TableModel. 尽管这不能解决您的问题,但不要调用fireTableDataChanged,这是TableModel的工作。

The problem is somewhere in your TableEditor. 问题出在TableEditor中。 I would guess you and not stopping cell editing. 我猜你不会停止单元格编辑。

Check out Table Button Column . 签出表格按钮列 It implements the renderer/editor for you. 它为您实现了渲染器/编辑器。 All you need to do is provide an Action to be invoked when you click on the button. 您需要做的就是提供一个在单击按钮时要调用的动作。

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

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