Ошибка при выборе строки таблицы из JTable с AbstractTableModel - PullRequest
0 голосов
/ 02 апреля 2012

У меня есть ArrayList типов модулей, у каждого модуля есть массив списков назначений.Я написал следующую TableModel, но когда что-то выбрано в таблице, у меня возникает проблема, и это приводит к тому, что мои ArrayLists выходят за пределы.Вот моя модель таблицы:

public class AssignmentsTableModel extends AbstractTableModel {
private ArrayList<Module> modules;
private static final String[] COLUMN_NAMES = {"Module Identifier", "Module Name", "Assignment Title", "Author", "Date Set", "Date Due", "Weighting"};

private int moduleID;
private int assignmentID;
private Module module;
private int totalNumberAssignments;

public AssignmentsTableModel(ArrayList<Module> modules) {
    moduleID = 0;
    assignmentID = 0;
    this.modules = modules;
    module = modules.get(moduleID);
    totalNumberAssignments = getRowCount();
}

public AssignmentsTableModel(Module module) {
    modules = new ArrayList<Module>();
    modules.add(module);
}

@Override
public int getRowCount() {
    int rowCount = 0;
    for(Module mod : modules){
        rowCount += mod.getAssignments().size();
    }
    return rowCount;
}

@Override
public int getColumnCount() {
    return COLUMN_NAMES.length;  //To change body of implemented methods use File | Settings | File Templates.
}

@Override
public Object getValueAt(int row, int column) {
    if(column%getColumnCount() == 0 && getRowCount() <= totalNumberAssignments){
        if(isAtLastAssignment(row, moduleID)){
            assignmentID = 0;
            moduleID += 1;
        }
    }

    module = modules.get(moduleID);
    ArrayList<Assignment> assignments = module.getAssignments();

    Assignment assignment = assignments.get(assignmentID);

    switch (column){
        case 0: return module.getIdentifier();
        case 1: return module.getTitle();
        case 2: return assignment.getTitle();
        case 3: return assignment.getAuthor();
        case 4: return assignment.getSet();
        case 5: return assignment.getDue();
        case 6: return assignment.getWeighting();
        default: return null;
    }


}

public String getColumnName(int columnIndex) {
    return COLUMN_NAMES[columnIndex];
}

public boolean isAtLastAssignment(int row, int moduleID){
    boolean atLast = false;
    ArrayList<Assignment> assignments = modules.get(moduleID).getAssignments();
    if(moduleID == 0){
        if(row == assignments.size()){
            atLast = true;
        }
    } else {
        int assignmentsSize = assignments.size() + getCurrentRowNumber(moduleID);
        if(row == assignmentsSize){
            atLast = true;
        }
    }

    return atLast;
}

public int getCurrentRowNumber(int moduleID){
    int rowNumber = 0;

    for(int i = 0; i < moduleID; i++){
        rowNumber = modules.get(i).getAssignments().size()-1;
    }

    return rowNumber;
}
}

Как вы можете видеть, я сохраняю moduleID как глобальные переменные, что хорошо при его первом запуске, но когда что-то выбирается, оно использует последние значения.Что еще я могу сделать, чтобы это не произошло?

Ответы [ 2 ]

5 голосов
/ 02 апреля 2012

Метод TableModel getValueAt () вызывается средством визуализации таблиц каждый раз, когда оно хочет получить значение ячейки, чтобы оно могло ее визуализировать.Это не связано (прямо или надежно) с тем, что вы щелкаете по строке таблицы и помечаете ее как выбранную.

Другими словами, вы не хотите изменять состояние вашей табличной модели какрезультат вызова метода getValueAt().

Было бы проще всего, если бы ваш метод getValueAt() использовал строку в качестве индекса в вашем массиве.Однако, похоже, у вас есть переменное количество строк для каждого модуля.В этом случае, если вы не можете алгоритмически сгенерировать правильный индекс, вы можете «сгладить» данные один раз в конструкторе и упростить код поиска.

То есть ваша табличная модель содержит:

private List<RowData> rowData

и внутренний класс, содержащий данные строки:

private static class RowData
{
  private Moddule;
  private Assignment assignment;

  ...
}

И в вашем конструкторе:

public AssignmentsTableModel(List<Module> modules)
{
  this.rowData = new ArrayList<Module>();

  for (Module module : modules)
  {
    for (Assignment assignment : module.getAssignments())
    {
      rowData.add(new RowData(module, assignment));
    }
  }
}

Это упрощает ваш getValueAt() метод:

@Override
public Object getValueAt(int row, int column) {
    final RowData row = this.rowData.get(row);

    switch (column){
        case 0: return row.getModule().getIdentifier();
        case 1: return row.getModule().getTitle();
        case 2: return row.getAssignment().getTitle();
        case 3: return row.getAssignment().Author();
        case 4: return row.getAssignment().getSet();
        case 5: return row.getAssignment().getDue();
        case 6: return row.getAssignment().getWeighting();
        default: return null;
    }
}
1 голос
/ 02 апреля 2012
  • выбор в основном не имеет ничего общего с TableModel, возможно, есть другие проблемы в остальном коде или методах, которые вы не разместили здесь,

  • для базового успеха Я пропускаю другие методы для AbstractTableModel, необходимые для добавления / изменения / удаления данных, строки или столбца от Model до View (и наоборот)

  • использовать DefaultTableModel , возможно, нет причин использовать AbstractTableModel

  • вы можете сравнить требуемые методы для базовых AbstractTableModel , использовать Object[][] или Vector<Vector<Object>>, реализованные непосредственно в API, а не другие типы Array или Hash,

  • пожалуйста, прочитайте turorial Как работает JTable

EDIT

@ Дин писал:

that I can't see another way around but when an update in the table happens

Это причины, по которым setXxxMethodsfireXxxXxx методами внутри) существует там, в руководстве Oracle о JTable упоминается больше раз об этом

...