JTable中的从属列

时间:2009-09-21 17:46:40

标签: java swing jtable

枝! 我有一个JTable。此JTable的列由JComboBox呈现。 我希望能够根据第1栏中选择的值更改第2栏的项目。

例如,如果用户在第1列中选择Microsoft,则在第2列中,他/她可以选择ado,wpf等。

有可能吗? 如果有可能,应该听哪些事件呢?

4 个答案:

答案 0 :(得分:0)

也许您可以根据此代码为基础;

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

这是一个有趣的页面:click

答案 1 :(得分:0)

只需创建自己的TableCellEditor,即在调用getTableCellEditorComponent时准备JComboBox的模型。像这样:

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

}

答案 2 :(得分:0)

Combo Box Table Editor为此提供了一种可能的解决方案。

答案 3 :(得分:0)

您在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()来获取业务对象)。事件机制将保持不变。这样做的好处是,从业务对象中读取选定的值可能比刮掉表格更容易。