如何修复Java中的'TableModel.setValueAt ArrayIndexOutOfBoundsException'错误

时间:2019-01-09 19:11:12

标签: java swing jtable

我有一个JTable应用程序。我需要更改单元格值并保存数据,但是只有索引小于或等于4的单元格才在数组范围内。

package fi.allu.neliojuuri;

import com.sun.glass.events.KeyEvent;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import javax.swing.event.CellEditorListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

public class Neliojuuri extends JPanel
    implements ActionListener, ItemListener, TableModelListener {

String newline = "\n";
private JTable table;
private JCheckBox rowCheck;
private JCheckBox columnCheck;
private JCheckBox cellCheck;
private ButtonGroup buttonGroup;
private JTextArea output;

private String[] sarakenimet = new String[70];
private String[] sisakkainen = new String[70];
private Object[][] ulkoinen = new String[71][71];

private DefaultTableModel oletusmalli = null;
private CellEditorListener solumuokkaaja = null;

public Neliojuuri() {
    super();
    setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));        

    for (int i = 0; i < 70; i++) {
            sarakenimet[i] = String.valueOf(i + 1);
        }

        for (int i = 0; i < sisakkainen.length; i++) {
            sisakkainen[i] = String.valueOf(i + 1);
        }

        for (int i = 0; i < ulkoinen.length; i++) {
            ulkoinen[i] = sisakkainen;
        }

    table = new JTable(ulkoinen, sarakenimet);
    table.setPreferredScrollableViewportSize(new Dimension(500, 210));
    table.setFillsViewportHeight(true);
    table.setRowHeight(30);

    TableColumnModel sarakeMalli = table.getColumnModel();
    for (int i = 0; i < 70; i++) {
        sarakeMalli.getColumn(i).setPreferredWidth(75);
    }

    oletusmalli = new javax.swing.table.DefaultTableModel();
    table.setModel(oletusmalli);

    String[] sarakenimet = new String[70];
    for (int i = 0; i < 70; i++) {
        sarakenimet[i] = String.valueOf(i + 1);
    }

    String[] sisakkainen = new String[70];
    for (int i = 0; i < sisakkainen.length; i++) {
        sisakkainen[i] = String.valueOf(i + 1);
    }
    Object[][] ulkoinen = new String[71][71];
    for (int i = 0; i < ulkoinen.length; i++) {
        ulkoinen[i] = sisakkainen;
    }

    oletusmalli.setColumnIdentifiers(sarakenimet);

    for (int count = 0; count < 70; count++){
        oletusmalli.insertRow(count, sisakkainen);
    }

    table.getSelectionModel().addListSelectionListener(new RowListener());
    table.getColumnModel().getSelectionModel().
            addListSelectionListener(new ColumnListener());
    add(new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 
        JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

    table.getModel().addTableModelListener(this);

    add(new JLabel("Selection Mode"));
    buttonGroup = new ButtonGroup();
    addRadio("Multiple Interval Selection").setSelected(true);
    addRadio("Single Selection");
    addRadio("Single Interval Selection");

    add(new JLabel("Selection Options"));
    rowCheck = addCheckBox("Row Selection");
    rowCheck.setSelected(true);
    columnCheck = addCheckBox("Column Selection");
    cellCheck = addCheckBox("Cell Selection");
    cellCheck.setEnabled(false);

    output = new JTextArea(5, 40);
    output.setEditable(false);
    output.setFont(new Font("Segoe UI", Font.PLAIN, 20));
    add(new JScrollPane(output));
}

private JCheckBox addCheckBox(String text) {
    JCheckBox checkBox = new JCheckBox(text);
    checkBox.addActionListener(this);
    add(checkBox);
    return checkBox;
}

private JRadioButton addRadio(String text) {
    JRadioButton b = new JRadioButton(text);
    b.addActionListener(this);
    buttonGroup.add(b);
    add(b);
    return b;
}

public void actionPerformed(ActionEvent e) {        
    JFileChooser tiedostovalitsin = new JFileChooser();        

    JMenuItem source = (JMenuItem)(e.getSource());
    if (source.getText() == "Save") {
        int palautusArvo = tiedostovalitsin.showSaveDialog(Neliojuuri.this);

        if (palautusArvo == JFileChooser.APPROVE_OPTION) {
            File tiedosto = tiedostovalitsin.getSelectedFile();
            // Tallenna tiedosto oikeasti
            for (int i = 0; i < oletusmalli.getRowCount(); i++) {
                System.out.println(oletusmalli.getValueAt(1, i).toString());
            }
            System.out.println(tiedosto.getName());
        }
    }

    String command = e.getActionCommand();
    //Cell selection is disabled in Multiple Interval Selection
    //mode. The enabled state of cellCheck is a convenient flag
    //for this status.
    if ("Row Selection" == command) {
        table.setRowSelectionAllowed(rowCheck.isSelected());
        //In MIS mode, column selection allowed must be the
        //opposite of row selection allowed.
        if (!cellCheck.isEnabled()) {
            table.setColumnSelectionAllowed(!rowCheck.isSelected());
        }
    } else if ("Column Selection" == command) {
        table.setColumnSelectionAllowed(columnCheck.isSelected());
        //In MIS mode, row selection allowed must be the
        //opposite of column selection allowed.
        if (!cellCheck.isEnabled()) {
            table.setRowSelectionAllowed(!columnCheck.isSelected());
        }
    } else if ("Cell Selection" == command) {
        table.setCellSelectionEnabled(cellCheck.isSelected());
    } else if ("Multiple Interval Selection" == command) {
        table.setSelectionMode(
                ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        //If cell selection is on, turn it off.
        if (cellCheck.isSelected()) {
            cellCheck.setSelected(false);
            table.setCellSelectionEnabled(false);
        }
        //And don't let it be turned back on.
        cellCheck.setEnabled(false);
    } else if ("Single Interval Selection" == command) {
        table.setSelectionMode(
                ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        //Cell selection is ok in this mode.
        cellCheck.setEnabled(true);
    } else if ("Single Selection" == command) {
        table.setSelectionMode(
                ListSelectionModel.SINGLE_SELECTION);
        //Cell selection is ok in this mode.
        cellCheck.setEnabled(true);
    }

    //Update checkboxes to reflect selection mode side effects.
    rowCheck.setSelected(table.getRowSelectionAllowed());
    columnCheck.setSelected(table.getColumnSelectionAllowed());
    if (cellCheck.isEnabled()) {
        cellCheck.setSelected(table.getCellSelectionEnabled());
    }
}

private void outputSelection() {
    output.append(String.format("Lead: %d, %d. ",
            table.getSelectionModel().getLeadSelectionIndex(),
            table.getColumnModel().getSelectionModel().
                    getLeadSelectionIndex()));
    output.append("Rows:");
    for (int c : table.getSelectedRows()) {
        output.append(String.format(" %d", c));
    }
    output.append(". Columns:");
    for (int c : table.getSelectedColumns()) {
        output.append(String.format(" %d", c));
    }
    output.append(".\n");
}

@Override
public void itemStateChanged(ItemEvent e) {
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}

@Override
public void tableChanged(TableModelEvent e) {
    int rivi = e.getFirstRow();
    int sarake = e.getColumn();
    TableModel malli = (TableModel)e.getSource();
    String sarakeNimi = malli.getColumnName(sarake);
    Object data = malli.getValueAt(rivi, sarake);
    MyTableModel taulumalli = new MyTableModel();
    taulumalli.setValueAt(data, rivi, sarake);
    System.out.println("rivi: " + rivi + " sarake: " + sarake + " data: " + data);
}

private void setValueAt(Object data, int rivi, int sarake) {
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}

private class RowListener implements ListSelectionListener {

    public void valueChanged(ListSelectionEvent event) {
        if (event.getValueIsAdjusting()) {
            return;
        }
        output.append("ROW SELECTION EVENT. ");
        outputSelection();
    }
}

private class ColumnListener implements ListSelectionListener {

    public void valueChanged(ListSelectionEvent event) {
        if (event.getValueIsAdjusting()) {
            return;
        }
        output.append("COLUMN SELECTION EVENT. ");
        outputSelection();
    }
}

class MyTableModel extends AbstractTableModel {

    private String[] columnNames = {"First Name",
        "Last Name",
        "Sport",
        "# of Years",
        "Vegetarian"};
    private Object[][] data = {
        {"Kathy", "Smith",
            "Snowboarding", new Integer(5), new Boolean(false)},
        {"John", "Doe",
            "Rowing", new Integer(3), new Boolean(true)},
        {"Sue", "Black",
            "Knitting", new Integer(2), new Boolean(false)},
        {"Jane", "White",
            "Speed reading", new Integer(20), new Boolean(true)},
        {"Joe", "Brown",
            "Pool", new Integer(10), new Boolean(false)}
    };

    public int getColumnCount() {
        return columnNames.length;
    }

    public int getRowCount() {
        return data.length;
    }

    public String getColumnName(int col) {
        return columnNames[col];
    }

    public Object getValueAt(int row, int col) {
        return data[row][col];
    }

    /*
     * JTable uses this method to determine the default renderer/
     * editor for each cell.  If we didn't implement this method,
     * then the last column would contain text ("true"/"false"),
     * rather than a check box.
     */
    public Class getColumnClass(int c) {
        return getValueAt(0, c).getClass();
    }

    /*
     * Don't need to implement this method unless your table's
     * editable.
     */
    public boolean isCellEditable(int row, int col) {
        //Note that the data/cell address is constant,
        //no matter where the cell appears onscreen.
        if (col < 2) {
            return false;
        } else {
            return true;
        }
    }

    /*
     * Don't need to implement this method unless your table's
     * data can change.
     */
    public void setValueAt(Object value, int row, int col) {
        data[row][col] = value;
        fireTableCellUpdated(row, col);
    }

}

public JMenuBar luoValikkoPalkki() {
    JMenuBar valikkopalkki = new JMenuBar();
    JMenu valikko = new JMenu("File");
    valikko.setMnemonic(KeyEvent.VK_F);
    valikko.getAccessibleContext().setAccessibleDescription(
            "File saving menu");
    valikkopalkki.add(valikko);

    JMenuItem valikkoitem = new JMenuItem("Save", KeyEvent.VK_S);
    valikkoitem.setAccelerator(KeyStroke.getKeyStroke(
            java.awt.event.KeyEvent.VK_S, ActionEvent.CTRL_MASK));
    valikkoitem.addActionListener(this);
    valikko.add(valikkoitem);
    return valikkopalkki;
}

/**
 * Create the GUI and show it. For thread safety, this method should be
 * invoked from the event-dispatching thread.
 */
private static void createAndShowGUI() {
    //Disable boldface controls.
    UIManager.put("swing.boldMetal", Boolean.FALSE);

    try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (Exception e) {
        e.printStackTrace();
    }
    //Create and set up the window.
    JFrame frame = new JFrame("Neliöjuuri");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    Neliojuuri neliojuuri = new Neliojuuri();
    frame.setJMenuBar(neliojuuri.luoValikkoPalkki());

    //Create and set up the content pane.
    Neliojuuri newContentPane = new Neliojuuri();
    newContentPane.setOpaque(true); //content panes must be opaque
    frame.setContentPane(newContentPane);

    //Display the window.
    frame.pack();
    frame.setVisible(true);
}

public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
}
}

Stacktrace:

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 5
at fi.allu.neliojuuri.Neliojuuri$MyTableModel.setValueAt(Neliojuuri.java:356)
at fi.allu.neliojuuri.Neliojuuri.tableChanged(Neliojuuri.java:261)
at javax.swing.table.AbstractTableModel.fireTableChanged(AbstractTableModel.java:296)
at javax.swing.table.AbstractTableModel.fireTableCellUpdated(AbstractTableModel.java:275)
at javax.swing.table.DefaultTableModel.setValueAt(DefaultTableModel.java:666)
at javax.swing.JTable.setValueAt(JTable.java:2744)
at javax.swing.JTable.editingStopped(JTable.java:4729)
at javax.swing.AbstractCellEditor.fireEditingStopped(AbstractCellEditor.java:141)
at javax.swing.DefaultCellEditor$EditorDelegate.stopCellEditing(DefaultCellEditor.java:368)
at javax.swing.DefaultCellEditor.stopCellEditing(DefaultCellEditor.java:233)
at javax.swing.JTable$GenericEditor.stopCellEditing(JTable.java:5473)
at javax.swing.DefaultCellEditor$EditorDelegate.actionPerformed(DefaultCellEditor.java:385)
at javax.swing.JTextField.fireActionPerformed(JTextField.java:508)
at javax.swing.JTextField.postActionEvent(JTextField.java:721)
at javax.swing.JTextField$NotifyAction.actionPerformed(JTextField.java:836)
at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1668)
at javax.swing.JComponent.processKeyBinding(JComponent.java:2882)
at javax.swing.JComponent.processKeyBindings(JComponent.java:2929)
at javax.swing.JComponent.processKeyEvent(JComponent.java:2845)
at java.awt.Component.processEvent(Component.java:6316)
at java.awt.Container.processEvent(Container.java:2239)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2297)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1954)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:835)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1103)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:974)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:800)
at java.awt.Component.dispatchEventImpl(Component.java:4760)
at java.awt.Container.dispatchEventImpl(Container.java:2297)
at java.awt.Window.dispatchEventImpl(Window.java:2746)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
at java.awt.EventQueue$4.run(EventQueue.java:733)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82) 

我希望能够更改表中的所有单元格值,但是我只能对其中的一部分进行更改。索引大于或等于5的单元格返回ArrayIndexOutOfBounds错误。

2 个答案:

答案 0 :(得分:0)

  

索引大于或等于5的单元格返回ArrayIndexOutOfBounds错误。

因为您创建了仅5行数据的“ MyTableModel”。如果模型中存在行/列,则只能更改数据。

为什么要使用Swing教程中的“ MyTableModel”作为TableModel?

此外,为什么每次生成“ tableChanged”事件时都要创建一个新的“ MyTableModel”?这意味着您将丢失以前的更改。

我建议如果您尝试将数据从一个表复制到另一个表,那么您需要创建一个DefaultTableModel,其行/列的数量与生成“ tableChanged”的其他TableModel中的行/列的数量相同”事件。

但是在不知道您的实际要求的情况下,我们无法提供适当的解决方案,只能消除错误。

答案 1 :(得分:0)

当执行到达taulumalli.setValueAt(data, rivi, sarake);内的行tableChanged()时,将有2个表模型。

第一个表模型由行table = new JTable(ulkoinen, sarakenimet);创建。该模型实际上已连接到显示的表。它有70行70列。

tableChanged()内部由行MyTableModel taulumalli = new MyTableModel();创建第二个表模型。即使这是一个表模型,也没有连接到任何表。它有5行5列。

当用户编辑表中的值时,将调用tableChanged()。在此方法内部,在前两行中,您从第一个表模型获得行索引和列索引(因为显示的表已连接到该表模型)。然后,将第一个表模型的这些行索引和列索引传递给第二个表模型的setValueAt()。这是不正确的,因为两个表模型具有不同的结构。这会导致错误。