Зависимые столбцы в JTable - PullRequest
2 голосов
/ 21 сентября 2009

Hie! У меня есть JTable. Столбцы этого JTable визуализируются JComboBox. Я хотел бы иметь возможность изменять элементы столбца 2 на основе значений, выбранных в столбце 1.

Например, если пользователь выбирает Microsoft в столбце 1, то в столбце 2 он может выбрать ado, wpf и т. Д.

Возможно ли это? Если это возможно, то какие события следует прослушивать, чтобы это сделать?

Ответы [ 4 ]

0 голосов
/ 23 сентября 2009

Что вы используете в качестве значений в TableModel?

Одним из решений было бы определение класса, скажем CategoryValue, который представляет список возможных элементов и выбранного элемента, и использование этого; затем прослушайте TableModelEvents и, когда значение в столбце 0 изменится, установите соответствующее значение в столбце 1. Ниже приведен простой пример.

Сначала TableModelListener:

model.addTableModelListener(new TableModelListener() {
  @Override
  public void tableChanged(TableModelEvent e) {
    if (e.getColumn() == 0) {
      int firstRow = e.getFirstRow();
      int lastRow = e.getLastRow();
      for (int row = firstRow; row <= lastRow; row++) { // note <=, not <
        CategoryValue parentValue = ((CategoryValue) model.getValueAt(row, 0));
        String parentSelection = parentValue.getSelection();
        List<String> childCategories = getChildCategories(parentSelection);
        CategoryValue newChildValue = new CategoryValue(childCategories);
        model.setValueAt(newChildValue , row, 1);
      }
    }
  }
});

(Реализация getChildCategories(String) зависит от того, откуда поступают ваши данные, но это может быть так же просто, как Map<String, List<String>>.)

Далее класс значений:

public class CategoryValue {
  private final String selection;
  private final List<String> categories;

  public CategoryValue(List<String> categories) {
    this(categories, categories.get(0));
  }

  public CategoryValue(List<String> categories, String selection) {
    assert categories.contains(selection);
    this.categories = categories;
    this.selection = selection;
  }

  public String getSelection() {
    return selection;
  }

  public List<String> getCategories() {
    return categories;
  }

  @Override
  public String toString() {
    return selection;
  }
}

Наконец, пользовательский редактор ячеек для класса значений:

public class CategoryCellEditor extends DefaultCellEditor {
  public CategoryCellEditor() {
    super(new JComboBox());
  }

  static List<CategoryValue> allValues(List<String> categories) {
    List<CategoryValue> allValues = new ArrayList<CategoryValue>();
    for (String value: categories) {
      allValues.add(new CategoryValue(categories, value));
    }
    return Collections.unmodifiableList(allValues);
  }

  @Override
  public Component getTableCellEditorComponent(JTable table, Object value, 
      boolean isSelected, int row, int column) {
    CategoryValue categoryValue = (CategoryValue) value;
    List<String> categories = categoryValue.getCategories();
    List<CategoryValue> allValues = CategoryValue.allValues(categories);
    ComboBoxModel cbModel = new DefaultComboBoxModel(allValues.toArray());
    ((JComboBox)editorComponent).setModel(cbModel);
    return super.getTableCellEditorComponent(table, categoryValue, 
      isSelected, row, column);
  }
}

Все сделано с одним прослушивателем событий, и приятным бонусом является то, что этому прослушивателю событий не важно, как таблица редактируется / обновляется или откуда происходят изменения / обновления.


Отредактировано, чтобы добавить: В качестве альтернативы, представьте каждую строку таблицы с некоторым бизнес-объектом, который фиксирует все выборы, сделанные для конкретной строки, и получите CellEditor для получения доступных вариантов из бизнес-объекта (используя аргумент row для getTableCellEditorComponent(), чтобы получить бизнес-объект). Механизм событий останется прежним. Преимущество этого состоит в том, что, вероятно, легче читать выбранные значения из бизнес-объекта, чем очищать таблицу.

0 голосов
/ 21 сентября 2009

Просто создайте свой собственный TableCellEditor, который подготавливает модель JComboBox к вызову getTableCellEditorComponent. Примерно так:

class MyEditor extends DefaultCellEditor{

    public MyEditor() {
        super(new JComboBox());
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        JComboBox combo = (JComboBox)editorComponent;

        Object column1Value = table.getValueAt(row, column-1);
        Object[] options = ... create options based on other value
        combo.setModel(new DefaultComboBoxModel(options));

        return super.getTableCellEditorComponent(table, value, isSelected, row, column);
    }

}
0 голосов
/ 21 сентября 2009

Редактор таблицы со списком предоставляет одно из возможных решений для этого.

0 голосов
/ 21 сентября 2009

Может быть, вы можете основать вас на этом коде;

table.getSelectionModel().addListSelectionListener(
    new ListSelectionListener() {
        public void valueChanged(ListSelectionEvent event) {
            int row = table.getSelectedRow();
            int column = table.getSelectedColumn();     
        }
    }
);

Это интересная страница: клик

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