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.