IndexOutOfBoundsException после вставки строки, сортировки таблицы и удаления строки - PullRequest
0 голосов
/ 08 мая 2018

В предыдущем вопросе ( Преобразование modelRowIndex в viewRowIndex для отсортированного JTable ) я указал, что я пытался создать «простой» JTable, который использовал TableModel, чтобы связать ArrayList с JTable, используя TableModel. Моей целью было - и остается - сохранить все встроенные в Java функции JTable, которые позволяют редактировать ячейки, сортировать строки и переставлять столбцы. Благодаря вашей помощи этот функционал теперь работает.

Я сейчас пытаюсь добавить возможность вставки и удаления строк таблицы. (Обновленный) пример, который я привожу здесь, работает ... ЗА ИСКЛЮЧЕНИЕМ ... при определенной последовательности операций выдается исключение IndexOutOfBoundsException. Вот мой код:

package tableexample;

import java.awt.Container;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;

public final class TableExample extends JFrame {

        List<REItem> REList;
        JTable tblREList;
        JButton btnAddInsertRE, btnDeleteRE;
        JScrollPane spMain;
        JFrame frame;
        Container pane;

    public TableExample() {
        // create and populate the ArrayList
        REList = new ArrayList<>();
        REList.add(new REItem("Template1", "Comment1"));
        REList.add(new REItem("Template2", "Comment2"));
        RETableModel retm = new RETableModel(REList);  // Connect the List to the TableModel
        // create GUI components
        frame = new JFrame ("Table Example");
        btnAddInsertRE = new JButton("Add/Insert");
        btnDeleteRE = new JButton("Delete");
        tblREList = new JTable(retm); 
        tblREList.setAutoCreateRowSorter(true);
        spMain = new JScrollPane(tblREList);
        // add button ActionListeners
        btnAddInsertRE.addActionListener((ActionEvent evt) -> { btnAddInsertREActionPerformed(evt); });
        btnDeleteRE.addActionListener((ActionEvent evt) -> { btnDeleteREActionPerformed(evt); });
        // place GUI components and make the GUI visible
        pane = frame.getContentPane();
        pane.setLayout (null);        
        pane.add(btnAddInsertRE);
        pane.add(btnDeleteRE);
        pane.add(spMain);
        btnAddInsertRE.setBounds (10, 10, 100, 25);
        btnDeleteRE.setBounds (120, 10, 100, 25);
        spMain.setBounds (10, 45, spMain.getPreferredSize().width, spMain.getPreferredSize().height);
        frame.setSize(spMain.getWidth() + 40, spMain.getHeight() + 95);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        
        frame.setVisible(true);
    } // end TableExample constructor

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            TableExample notUsed = new TableExample();
        });
    } //end main

    private void btnAddInsertREActionPerformed(ActionEvent evt) {                                             
        // Add a FileSelection object to the ArrayList
        int r = tblREList.getSelectedRow();                         // get row selection, if any
        if (r < 0) {                                                // no row selected
            REList.add(new REItem("NewTemplate", "NewComment"));    //   append new item to end
            r = REList.size()-1;                                    //   get index to new item
        } else {                                                    // else no row selected
            REList.add(r, new REItem("NewTemplate", "NewComment")); //   insert above selected row
        }                                                           // row selected or not
        spMain.setViewportView(tblREList);                          // repaint the updated table
        tblREList.getSelectionModel().setSelectionInterval(r, r);   // select the new row
    }                                            

    private void btnDeleteREActionPerformed(ActionEvent evt) {                                          
        int[] selRows = tblREList.getSelectedRows();                // see if any rows are selected
        if (selRows.length>0) {                                     // at least one row is selected
            for (int r=selRows.length-1; r>=0; r--) {               //   delete each row, from the bottom up,
                REList.remove(r);                                   //     so that indexes are correct and
            }                                                       //       don't change with each delete
            tblREList.clearSelection();                             // clear the row selection data
            spMain.setViewportView(tblREList);                      // repaint the updated table
        } else {                                                    // else no row(s) selected
            JOptionPane.showMessageDialog(null, "Must select at least one item to delete");
        }                                                           // no row selected
    } // end btnDeleteREActionPerformed

    public final class REItem {
        String template;
        String comment;

        public REItem(String tmp, String cmt) {
            this.template = tmp;
            this.comment = cmt;
        }
    } // end class REItem

    public class RETableModel extends AbstractTableModel {

        private List<REItem> reList = new ArrayList();
        private final String[] columnNames = { "Template", "Comment" };

        public RETableModel(List<REItem> list){
             this.reList = list;
        }

        @Override
        public String getColumnName(int column){
             return columnNames[column];
        }

        @Override     
        public int getRowCount() {
            return reList.size();
        }

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

        @Override
        public Object getValueAt(int row, int column) {
            switch (column) {
                case 0: return reList.get(row).template;
                case 1: return reList.get(row).comment;
               }
               return null; // default case
       }

        @Override
        public boolean isCellEditable(int row, int column) {
            return true;
        }

        @Override
        public Class<?> getColumnClass(int column){
            switch (column){
                case 0: return String.class;
                case 1: return String.class;
            }
            return null; // default case
        }

        @Override
        public void setValueAt(Object value, int row, int column) {
            switch (column) {
                case 0: reList.get(row).template = value.toString(); break;
                case 1: reList.get(row).comment = value.toString(); break;
               }
            // uncommenting the below often causes IndexOutOfBoundsException: Invalid range exception
            fireTableCellUpdated(row, column); 
        } // end setValueAt

    } // end RETableModel

} // end class TableExample

Проблема может быть воспроизведена следующим образом: Запустите приведенный выше пример, нажмите кнопку «Добавить / вставить», чтобы добавить новую строку в таблицу, щелкните заголовок любого столбца, чтобы заново отсортировать таблицу, затем нажмите «Удалить». Кнопка: генерируется «IndexOutOfBoundsException», указывающее, что индекс «строки», указанный методом getValueAt TableModel, имеет недостатки.

Я предполагаю, что проблема связана с необходимостью использования моего метода (ов) TableModel.getValueAt (и, возможно, .setValueAt ???) для преобразования между индексами столбцов TableModel и индексами столбцов View, но, на мой взгляд, я могу не понять, как или где сделать преобразование. Более того, этот вопрос ( Преобразовать modelRowIndex в viewRowIndex для отсортированного JTable ) указывает на то, что необходимо преобразование между TableModel и View-индексами строк, И что повторная сортировка таблицы ДОЛЖНА произойти до того, как будет выполнено преобразование индекса.

Как ни старайся, я не могу понять, как выполнить преобразование и / или как убедиться, что преобразование произойдет ПОСЛЕ ТОГО, КАК таблица обновлена ​​и повторно отсортирована. Нужен ли мне слушатель? Если так, то как это должно выглядеть?

Можете ли вы дать некоторые разъяснения и помочь?

1 Ответ

0 голосов
/ 08 мая 2018

Прежде всего, имена переменных НЕ должны начинаться с символа верхнего регистра. Это соглашение Java, и оно портится из-за форматирования кода, который вы публикуете, что затрудняет чтение кода. Исправьте свои переменные и следуйте соглашениям Java.

ArrayList должен использоваться только для первоначального добавления данных в модель.

После этого обновления должны быть выполнены для TableModel, а не для ArrayList. Поэтому вам нужно добавить методы к вашей TableModel, такие как addREItem(...) и removeREItem(...).

См. Модель таблицы строк для пошагового примера того, как построить пользовательскую TableModel для данного объекта, включая как код добавить ??? (...) и удалить? ?? (...) метод.

И если вы хотите удалить выбранные строки из таблицы, посмотрите: Как удалить несколько строк из базы данных JTable одновременно для рабочих примеров, показывающих, как это можно сделать с помощью команды remove ??? (...) метод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...