Dependent columns in JTable

Hie! I have a JTable. The columns of this JTable are rendered by the JComboBox. I would like to be able to change the items in column 2 based on the values โ€‹โ€‹selected in column 1.

For example, if the user selects Microsoft in column 1, then in column 2, he can select ado, wpf, etc.

Is it possible? If possible, what events should you listen for to do this?

+2


source to share


4 answers


Combo Box Table Editor provides one possible solution for this.



0


source


Maybe you can base you on this code;

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

      



This is an interesting page: click

0


source


Just create your own TableCellEditor that will fit the JComboBox model when you call getTableCellEditorComponent. Something like that:

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


source


What are you using as values โ€‹โ€‹in TableModel

?

One solution would be to define a class, for example CategoryValue

, that represents a list of possible items and a selected item and use it; then listen TableModelEvents

and when the value in column 0 changes, set the corresponding value in column 1. Below is a simple example.

First 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);
      }
    }
  }
});

      

(The implementation getChildCategories(String)

depends on where your data is coming from, but it could be as simple as Map<String, List<String>>

.)

Further the value class:

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;
  }
}

      

Finally, a custom cell editor for the value class:

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);
  }
}

      

Everything is done with one event listener, and a nice bonus is that the event listener doesn't care how the table is being edited / updated or where the changes / updates come from.


Edited to add: Alternatively, present each table row with some kind of business object that captures all the choices made for a particular row and CellEditor

gets the available choices from the business object (using an row

argument getTableCellEditorComponent()

to get the business object). The event mechanism will remain the same. This has the advantage that it is probably easier to read the selected values โ€‹โ€‹from the business object than to clear the table.

0


source







All Articles