有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

自定义组件JTable的java添加和删除行

我正在一步一步地做

Changing LookAndFeel of JTable of Custom Component

注意我有更多的自定义列,这些代码是用于演示海豚的

现在,我想使用一个从DefaultTableModel扩展的类来实现addrow和deleterow,该类用于填充自定义对象的JTable

这是我的代码:

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

public class LAF_TableCustom_AddDelRow {

  static JFrame frame = new JFrame();

  public JComponent makeUI() {

    String[] hdrsObjects = {"PanelSpinnerRadioButton Class Column"};
    Object[][] objectMatrix = new Object[3][1];
    objectMatrix[0][0] = new PanelSpinnerRadioButtonData(false, 10, 40);
    objectMatrix[1][0] = new PanelSpinnerRadioButtonData(true,  20, 40);
    objectMatrix[2][0] = new PanelSpinnerRadioButtonData(false, 30, 40);

//    JTable table = new JTable(new DefaultTableModel(objectMatrix, hdrsObjects)) {
    JTable table = new JTable(new PSRBTableModel(objectMatrix, hdrsObjects)) {
      @Override public void updateUI() {
        super.updateUI();
        setRowHeight(30);
        TableColumn tc = getColumn("PanelSpinnerRadioButton Class Column");
        tc.setCellRenderer(new PSRBTableCellRenderer());
        tc.setCellEditor(new PSRBTableCellEditor());
      }
    };

    JScrollPane scrollPane = new JScrollPane(table);
    scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
    scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

    JPanel pV = new JPanel();
    pV.setLayout(new BoxLayout(pV, BoxLayout.PAGE_AXIS));

    JButton bAddRow = new JButton("Add Row");
    bAddRow.addActionListener(new ActionListener() {
      @Override public void actionPerformed(ActionEvent evt) {
        ((PSRBTableModel)table.getModel()).addRow(
            new Object[] { new PanelSpinnerRadioButtonData(false, 10, 40) }
        );
//        ((DefaultTableModel)table.getModel()).addRow(
//            new Object[] { new PanelSpinnerRadioButtonData(false, 10, 40) }
//        );
      }
    });

    pV.add(bAddRow);
    pV.add(scrollPane);
    return pV;
  }

  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
    frame.getContentPane().add(new LAF_TableCustom_AddDelRow().makeUI());
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.setSize(320, 240);
    frame.setVisible(true);
    });
  }

}

class PanelSpinnerRadioButtonData {
  private boolean opt02 = false;
  private Integer from = 0;
  private Integer size = 1;

  PanelSpinnerRadioButtonData() {
    this(false, 5, 10);
  }
  PanelSpinnerRadioButtonData(boolean opt02, Integer from, Integer size) {
    this.opt02 = opt02;
    this.from = from;
    this.size = size;
  }
  public boolean getOption() {
    return opt02;
  }
  public Integer getFrom() {
    return from;
  }
  public Integer getSize() {
    return size;
  }
}

class PanelSpinnerRadioButton extends JPanel {
  public final JRadioButton jrbOption01 = new JRadioButton("01");
  public final JRadioButton jrbOption02 = new JRadioButton("12");
  public final JSpinner jspnValues = new JSpinner(new SpinnerNumberModel(5, 0, 10, 1));
  public final JButton jbRemoveRow = new JButton("Del Row");

  private final JPanel panel = new JPanel();

  PanelSpinnerRadioButton() {
    this(new PanelSpinnerRadioButtonData(false, 20, 40));
  }
  PanelSpinnerRadioButton(PanelSpinnerRadioButtonData data) {
    super();

    panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
    panel.add(jrbOption01);
    panel.add(jrbOption02);
    panel.add(jspnValues);
    panel.add(jbRemoveRow);

    jbRemoveRow.addActionListener(new ActionListener() {
      @Override public void actionPerformed(ActionEvent e) {
        JTable table = (JTable)SwingUtilities.getAncestorOfClass(
            JTable.class, (Component) e.getSource());
        int row = table.getEditingRow();
        table.getCellEditor().stopCellEditing();
//        ((DefaultTableModel) table.getModel()).removeRow(row);
        ((PSRBTableModel) table.getModel()).removeRow(row);

      }
    });

    ButtonGroup bg = new ButtonGroup();
    bg.add(jrbOption01);
    bg.add(jrbOption02);
    ((SpinnerNumberModel) jspnValues.getModel()).setMaximum(data.getSize());
    setData(data);

    init();
  }
  private void init() {
    setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
    setBackground(new Color(0, 0, 0, 0));
    add(panel);
  }
  public void setData(PanelSpinnerRadioButtonData data) {
    if (data.getOption()) {
      jrbOption02.setSelected(true);
    } else {
      jrbOption01.setSelected(true);
    }
    ((SpinnerNumberModel) jspnValues.getModel()).setValue(data.getFrom());
  }
  public PanelSpinnerRadioButtonData getData() {
    return new PanelSpinnerRadioButtonData(
        jrbOption02.isSelected(),
        (Integer) ((SpinnerNumberModel) jspnValues.getModel()).getValue(),
        (Integer) ((SpinnerNumberModel) jspnValues.getModel()).getMaximum());
  }

}

class PSRBTableCellRenderer implements TableCellRenderer {
  private final PanelSpinnerRadioButton renderer = new PanelSpinnerRadioButton();
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    if (value instanceof PanelSpinnerRadioButtonData) {
      renderer.setData((PanelSpinnerRadioButtonData) value);
    }
    return renderer;
  }
}

class PSRBTableCellEditor extends AbstractCellEditor implements TableCellEditor {
  private final PanelSpinnerRadioButton editor = new PanelSpinnerRadioButton();
  @Override public Object getCellEditorValue() {
    return editor.getData();
  }
  @Override public Component getTableCellEditorComponent(
      JTable table, Object value, boolean isSelected, int row, int column) {
    if (value instanceof PanelSpinnerRadioButtonData) {
      editor.setData((PanelSpinnerRadioButtonData) value);
    }
    return editor;
  }

}

//class PSRBTableModel extends AbstractTableModel {
class PSRBTableModel extends DefaultTableModel {

  private final Object[][] data;
  private final Object[] columns;

  public PSRBTableModel(Object[][] data, Object[] columns) {
    this.data = data;
    this.columns = columns;
  }

  @Override public Object getValueAt(int rowIndex, int columnIndex) {
    if (data != null) {
      if (data.length > 0) {
        return data[rowIndex][columnIndex];
      }
    }
    return null;
  }

  @Override public int getColumnCount() {
    return ((columns == null) ? 0: columns.length);
  }

  @Override public int getRowCount() {
    return ((data == null) ? 0: data.length);
  }

  @Override public Class getColumnClass(int columnIndex) {
    if (data != null) {
      if (data.length > 0) {
        if (data[0][columnIndex] instanceof PanelSpinnerRadioButton) {
          return PanelSpinnerRadioButton.class;
        }
        return data[0][columnIndex].getClass();
      }
    }
    return Object.class;
  }

  @Override public boolean isCellEditable(int rowIndex, int columnIndex) {
    if (data != null) {
      if (data.length > 0) {
        if (data[0][columnIndex] instanceof PanelSpinnerRadioButton) {
          return true;
        }
      }
    }
    return true;
  }

  @Override public void setValueAt(Object value, int row, int col) {
    data[row][col] = value;
    fireTableCellUpdated(row, col);
  }

  @Override public String getColumnName(int columnIndex) {
    return (String)columns[columnIndex];
  }

  @Override public void removeRow(int row) {
    fireTableRowsDeleted(row, row);
    System.out.println("fireTableRowsDeleted(" + row + ", " + row + ");");
  }

  @Override public void addRow(Object[] rowData) {
    super.addRow(rowData);
  }
}

问题

当我按下Del Row按钮时,该行没有被删除! 我得到了与行相关的打印消息:fireTableRowsDeleted(ROW, ROW);I

当我按下Add Row键时,我得到了这个异常

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 3 > 0
    at java.util.Vector.insertElementAt(Vector.java:598)
    at javax.swing.table.DefaultTableModel.insertRow(DefaultTableModel.java:374)
    at javax.swing.table.DefaultTableModel.addRow(DefaultTableModel.java:350)
    at javax.swing.table.DefaultTableModel.addRow(DefaultTableModel.java:361)
    at PSRBTableModel.addRow(LAF_TableCustom_AddDelRow.java:248)
    at LAF_TableCustom_AddDelRow$2.actionPerformed(LAF_TableCustom_AddDelRow.java:45)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)

如何使用我的自定义DefaultTableModel覆盖相应的方法来执行这些操作(removeRow、addRow)

这个answer不起作用

编辑

  //Doesn't Work
  @Override public void removeRow(int row) {
    super.removeRow(row);
  }

  //Doesn't Work
  @Override public void removeRow(int row) {
    getDataVector().removeElementAt(row);
    fireTableRowsDeleted(row, row);
  }

  //Doesn't Work (Not overriding the Method)
  //  @Override public void removeRow(int row) {
  //    getDataVector().removeElementAt(row);
  //  }

共 (2) 个答案

  1. # 1 楼答案

    基本问题是,DefaultTableModel已经有一个Vector支持,它管理行/列数据。但是您对它的扩展,实现了它自己的数据结构,使得Vector是多余的

    如果你花时间看一下DefaultTabelModel的源代码,你会发现addRow(Object[])调用addRow(Vector),它利用了getRowCount,调用了它的实现

    /**
     *  Adds a row to the end of the model.  The new row will contain
     *  <code>null</code> values unless <code>rowData</code> is specified.
     *  Notification of the row being added will be generated.
     *
     * @param   rowData          optional data of the row being added
     */
    public void addRow(Vector rowData) {
        insertRow(getRowCount(), rowData);
    }
    
    /**
     *  Adds a row to the end of the model.  The new row will contain
     *  <code>null</code> values unless <code>rowData</code> is specified.
     *  Notification of the row being added will be generated.
     *
     * @param   rowData          optional data of the row being added
     */
    public void addRow(Object[] rowData) {
        addRow(convertToVector(rowData));
    }
    

    这意味着Vector中没有任何内容,但您的代码表示有3行,这基本上触发了所有核心问题

    你有一个选择。要么使用DefaultTableModel扔掉你自己的数据结构(datacolumns),要么使用类似AbstractTableModel的东西,这将迫使你实现你自己的数据结构

    最基本的建议可能是第一个,因为DefaultTableModel应该能够提供您似乎需要的基本基本需求

    举一个非常基本的例子:

    class PSRBTableModel extends DefaultTableModel {
    
        public PSRBTableModel(Object[][] data, Object[] columns) {
            super(data, columns);
        }
    
        @Override
        public Class getColumnClass(int columnIndex) {
            if (getRowCount() > 0) {
                Object value = getValueAt(0, columnIndex);
                if (value instanceof PanelSpinnerRadioButton) {
                    return PanelSpinnerRadioButton.class;
                }
            }
            return Object.class;
        }
    
        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return getColumnClass(columnIndex) == PanelSpinnerRadioButton.class;
        }
    }
    
  2. # 2 楼答案

    从您自己的代码开始:

    编辑PSRBTableModel

      private Object[][] data; //Can't be final, you are changing!!!
    

    现在的方法是:

      @Override 
      public void removeRow(int row) {
        Object[][] newData = new Object[data.length - 1][data[0].length];
        int rown = 0;
        for (int row1 = 0; row1 <data.length; row1++) {
          if (row1 != row) {
            for (int col = 0; col < data[0].length; col++) {
              newData[rown][col] = data[row1][col];
            }
            rown++;
          }
        }
        data = newData;
      }
    
      @Override 
      public void addRow(Object[] rowData) {
        Object[][] newData = new Object[data.length + 1][data[0].length];
        for (int row = 0; row <data.length; row++) {
          for (int col = 0; col < data[0].length; col++) {
            newData[row][col] = data[row][col];
          }
        }
        int maxCol = data[0].length < rowData.length?data[0].length:rowData.length;
        for (int col = 0; col < maxCol; col++) {
          newData[data.length][col] = rowData[col];
        }
        data = newData;
      }
    

    根据您的需求调整代码(检查一些空对象以避免异常),我不知道您是如何使用的

    现在, 如果要从AbstractTableModel扩展PSRBTableModel类,请删除@Override标记

    class PSRBTableModel extends AbstractTableModel { 
    

    但是,如果你的PSRBTableModel类是从DefaultTableModelclass扩展而来的,那就离开它们吧

    class PSRBTableModel extends DefaultTableModel {
    

    在你的LAF_TableCustom_AddDelRow课上:

        JButton bAddRow = new JButton("Add Row");
        bAddRow.addActionListener(new ActionListener() {
          @Override public void actionPerformed(ActionEvent evt) {
            ((PSRBTableModel)table.getModel()).addRow(
                new Object[] { new PanelSpinnerRadioButtonData(false, 10, 40) }
            );
            table.updateUI();
          }
        });
    

    在你的PanelSpinnerRadioButton课上

        jbRemoveRow.addActionListener(new ActionListener() {
          @Override public void actionPerformed(ActionEvent e) {
            JTable table = (JTable)SwingUtilities.getAncestorOfClass(
                JTable.class, (Component) e.getSource());
            int row = table.getEditingRow();
            table.getCellEditor().stopCellEditing();
            ((PSRBTableModel)table.getModel()).removeRow(row);
            // table.updateUI();
          }
        });