Java JTable中的依赖列

Java JTable中的依赖列,java,swing,jtable,Java,Swing,Jtable,嗨! 我有一张表格。此JTable的列由JComboBox呈现。 我希望能够根据第1列中选择的值更改第2列的项目 例如,如果用户在第1列中选择Microsoft,则在第2列中可以选择ado、wpf等 可能吗? 如果可能的话,应该听哪些事件呢?也许你可以基于此代码 table.getSelectionModel().addListSelectionListener( new ListSelectionListener() { public void valueChanged

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

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

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

也许你可以基于此代码

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

这是一个有趣的页面:

也许您可以基于此代码

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

这是一个有趣的页面:

只需制作自己的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);
    }

}

只需制作自己的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);
    }

}

提供了一种可能的解决方案。

提供了一种可能的解决方案。

您在
表格模型中使用的值是什么

一种解决方案是定义一个类,比如说
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);
      }
    }
  }
});
最后,值类的自定义单元格编辑器:

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);
  }
}
公共类CategoryCellEditor扩展了DefaultCellEditor{
公共类别查询编辑器(){
super(新JComboBox());
}
静态列表所有值(列表类别){
List allValues=new ArrayList();
用于(字符串值:类别){
添加(新类别值(类别,值));
}
返回集合。不可修改列表(所有值);
}
@凌驾
公共组件getTableCellEditorComponent(JTable表、对象值、,
布尔值(选定,int行,int列){
CategoryValue CategoryValue=(CategoryValue)值;
列表类别=categoryValue.getCategories();
列出所有值=类别值。所有值(类别);
ComboBoxModel cbModel=新的默认ComboxModel(allValues.toArray());
((JComboBox)编辑器组件).setModel(cbModel);
返回super.getTableCellEditorComponent(表、类别值、,
i选定,行,列);
}
}
所有这些都是通过一个事件监听器完成的,一个很好的好处是,该事件监听器不关心如何编辑/更新表,也不关心编辑/更新来自何处



编辑以添加:或者,用一些业务对象表示表中的每一行,这些业务对象捕获为特定行所做的所有选择,并让
CellEditor
从业务对象获取可用的选择(使用
row
参数来
getTableCellEditorComponent()
获取业务对象)。事件机制将保持不变。这样做的好处是,从业务对象中读取所选值可能比从表中刮取值更容易。

您在
表模型中使用什么作为值

一种解决方案是定义一个类,比如说
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);
      }
    }
  }
});
最后,值类的自定义单元格编辑器:

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);
  }
}
公共类CategoryCellEditor扩展了DefaultCellEditor{
公共类别查询编辑器(){
super(新JComboBox());
}
静态列表所有值(列表类别){
List allValues=new ArrayList();
用于(字符串值:类别){
添加(新类别值(类别,值));
}
返回集合。不可修改列表(所有值);
}
@凌驾
公共组件getTableCellEditorComponent(JTable表、对象值、,
布尔值(选定,int行,int列){
CategoryValue CategoryValue=(CategoryValue)值;
列表类别=categoryValue.getCategories();
列出所有值=类别值。所有值(类别);
ComboBoxModel cbModel=新的默认ComboxModel(allValues.toArray());
((JComboBox)编辑器组件).setModel(cbModel);
返回super.getTableCellEditorComponent(表、类别值、,
i选定,行,列);
}
}
所有这些都是通过一个事件监听器完成的,一个很好的好处是,该事件监听器不关心如何编辑/更新表,也不关心编辑/更新来自何处


编辑以添加:或者,用一些业务对象表示表中的每一行,这些业务对象捕获为特定行所做的所有选择,并让
CellEditor
从业务对象获取可用的选择(使用
row
参数来
getTableCellEditorComponent()
获取业务对象)。事件机制将保持不变。这样做的优点是,从业务对象中读取所选的值可能比刮表更容易