Удалить строку в JTable с помощью RowFilter

У меня есть настольное приложение Swing с JTable. При добавлении строк в JTable проблем нет. Я также могу сортировать (используя JTable.autoCreateRowSorter), а затем плавно удалять строку (используя convertRowIndexToModel).

Я сталкиваюсь с проблемами при поиске в текстовом поле, где JTable обновляется, чтобы отображать только строки, содержащие запрос. Когда я пытаюсь удалить строку после ввода поискового запроса, начинают происходить странные вещи:

public class EmployeeRecords extends javax.swing.JFrame {

ArrayList<Employee> employees = new ArrayList <Employee> ();

...
private void search(String query) {
    //Create new table sorter for the table
    TableRowSorter sorter = new TableRowSorter(employeeTable.getModel());
    //Add row filter to the tablerowsorter (regex)
    sorter.setRowFilter(RowFilter.regexFilter("(?i).*\\Q"+query+"\\E.*") );
    //Apply the results to the output table
    employeeTable.setRowSorter(sorter);
}

private void deleteButtonActionPerformed() {
    //Get the index of the employee to delete
    int employee = employeeTable.convertRowIndexToModel(
            employeeTable.getSelectedRow());

    employees.remove(employee); //This is where the IndexOutOfBoundsException occurs

    refreshTable();
}

/**
 * Refreshes the employee table. Uses the "employees" class array list to
 * populate the rows.
 */
private void refreshTable() {
    //Delete all the rows in the table
    DefaultTableModel tbm = (DefaultTableModel) employeeTable.getModel();
    for (int i=employeeTable.getRowCount()-1; i >= 0; i--) {
        tbm.removeRow(i);
    }

    //For every employee
    for (int i=0; i < employees.size(); i++) {
        //Add the employee's data to a table row
        tbm.addRow(employees.get(i).getData());
    }
}
}

Я попытаюсь удалить строку, и иногда она дублирует строку, которую я хотел удалить. В других случаях я получаю исключение IndexOutOfBoundsException, вероятно, из-за перепутанных индексов.

Я не понял решения для кого-то с такой же проблемой так как я мало что знаю о Swing Timers и тому подобном.

Я также позаботился о том, чтобы преобразовать индексы строк в модель, как предложено в этом вопросе.

Есть идеи, как это исправить?

ОБНОВЛЕНИЕ: Это основной скриншот того, что происходит. введите описание изображения здесьНайдите "a" и "a" и "aa": введите здесь описание изображения

И когда я выбираю «a» и нажимаю «Удалить выбранное», это результат: введите здесь описание изображения

Теперь, если я попытаюсь удалить «аа», я в конечном итоге получу исключение IndexOutOfBoundsException.

ОБНОВЛЕНИЕ 2: Вот класс сотрудников:

public class Employee {

//Class fields
Integer employeeIdNumber;
String firstName, lastName, startDate;
Double annualSalary;

/* Constructor for the Employee object */
public Employee(Integer employeeIdNumber, String firstName, String lastName, 
        Double annualSalary, String startDate) {

    //Assign paramters to class fields
    this.employeeIdNumber = employeeIdNumber;
    this.firstName = firstName;
    this.lastName = lastName;
    this.annualSalary = annualSalary;
    this.startDate = startDate;
}

/**
 * Gets the data for the employee (ID, firstname, lastname, annual salary,
 * and start date, in that order)
 * 
 * @return an Object[] of the abovementioned employee data.
 */
public Object[] getData() {
    return new Object[] {
        employeeIdNumber,
        firstName,
        lastName,
        annualSalary,
        startDate
    };
}
}

ИСПРАВЛЕНИЕ (спасибо camickr): я изменил следующий код для кнопки удаления

private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {                                             

    DefaultTableModel tbm = (DefaultTableModel) employeeTable.getModel();
    //Get the index of the employee to delete
    int employee = employeeTable.convertRowIndexToModel(
            employeeTable.getSelectedRow());

    //Delete the row directly
    tbm.removeRow(employee);
    //as well as delete the employee from the array
    employees.remove(employee);
} 

person jessechk    schedule 23.03.2013    source источник


Ответы (2)


Не уверен, что понимаю ваш дизайн. У вас есть DefaultTableModel, а также список ArrayList, содержащий ваших сотрудников.

Данные о сотрудниках должны храниться в TableModel. Не должно быть необходимости воссоздавать TableModel, так как вы должны просто удалить строку из модели, и таблица перерисуется.

Кроме того, в качестве примечания при использовании DefaultTableModel вы просто используете следующее, чтобы удалить все строки:

model.setRowCount(0);
person camickr    schedule 23.03.2013
comment
Ты прав. Здесь не обязательно должен быть ArrayList. Однако это часть моего задания, где мы должны использовать Object ArrayList (создать объект, получить от него поля). Однако использование tbm.removeRow(employee) работает безупречно! (без повторного создания/обновления таблицы) - person jessechk; 23.03.2013

При удалении всех строк в методе refreshTable попробуйте изменить логику

while(employeeTable.getRowCount() > 0) {
    tbm.removeRow(0);
}

Это гарантирует, что вы не получите IndexOutOfBoundsException. Также может решить другую проблему отображения повторяющихся строк.

person Ravindra Gullapalli    schedule 23.03.2013
comment
Я изменил предложенный вами код (намного чище, чем мой). Но я все еще получаю те же проблемы .. - person jessechk; 23.03.2013
comment
Вы можете опубликовать оба класса? - person Ravindra Gullapalli; 23.03.2013
comment
Я разместил класс сотрудников - person jessechk; 23.03.2013