tags:

views:

257

answers:

4

Hie! I have a JTable. Columns of this JTable are rendered by JComboBox. I would like to be able to change items of column 2 on the basis of values selected in column 1.

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

Is it possible ? If it is possible, than which events should be listened to do it ?

A: 

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 intresting page: click

Martijn Courteaux
A: 

Just make your own TableCellEditor that preps the JComboBox's model on the call to getTableCellEditorComponent. Something like this:

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

}
CarlG
A: 

The Combo Box Table Editor provides one possible solution for this.

camickr
Thanks, camickr !That solved my problem.
sr
A: 

What are you using as values in your TableModel?

One solution would be to define a class, say CategoryValue, that represents a list of possible items and a selected item, and use that; then listen for TableModelEvents and when a value in column 0 changes, set the corresponding value in column 1. A simple example is below.

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

(Implementing getChildCategories(String) depends on where your data is coming from, but it could be as simple as a Map<String, List<String>>.)

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

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


Edited to add: Alternatively, represent each row of the table with some business object that captures all the choices made for a particular row, and have the CellEditor get the available choices from the business object (using the row argument to getTableCellEditorComponent() to get the business object). The event mechanism would remain the same. This has the advantage that it's probably easier to read the selected values from the business object than to scrape the table.

David Moles