如何仅在 JTable 的特定单元格中设置 JComboBox

How to set a JComboBox only in specific cell in a JTable

我只想在假定具有值列表的单元格内添加 JComboBox。下面是我的代码,但它在列的所有单元格中添加了组合框。让我知道我的代码中缺少什么以仅在选定的单元格上设置组合框。

     public class PropertiesTableModel extends AbstractTableModel{

 //this method is called to set the value of each cell
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Field field= (Field) fieldList.get(rowIndex);

        if(columnIndex==0){
            String dataType=field.getFieldDef().getDataType();
            return PropertiesPanel.getPpIns().getDataTypeIcon(dataType);
        }

        if(columnIndex==1){
            return field.getFieldDef().getfName();
        }
        else if (columnIndex==2){
             if(field.getFieldDef().getListValue().size()>0){
                 return createValueListCombo(field.getFieldDef().getListValue());
             }

            return field.getDefaultValue();
        }
        else{
            return null;
        }
    }

        public JComboBox createValueListCombo(List<Value> valueList){
        TableColumn valColumn = table.getColumnModel().getColumn(2);
        JComboBox comboBox=new JComboBox();

        for (Value val: valueList) {
            comboBox.addItem(val.getDescription());
        }
        comboBox.setSelectedIndex(0);
        valColumn.setCellEditor(new DefaultCellEditor(comboBox));
        return comboBox;
    }
}

其实很简单,两种方式都可以搞定

首先,您的模型应该通知 editor/table 当前单元格有值列表。

public class PropertiesTableModel extends AbstractTableModel {
     @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        // previous stuff
        if (columnIndex == 2) {
            // return the actually selected value, 
            // not the first value of the list!
            // also the values changed by setValueAt() must be considered.
            return null; // implement it!
        }
    }

    public List<Object> getPossibleValues(int row, int column) {
        // this method should return possible values to select.
        // if cell has no possible values and should be editeb 
        // by a text field this methos should return null
        if (column == 2) {
             Field field= (Field) fieldList.get(rowIndex);
             if (field.getFieldDef().getListValue().size() > 0) {
                 return field.getFieldDef().getListValue();
             }
             return null; // probably something else for non-list values
         }
    }

    public void setValueAt(int row, int column) {
        // you need to store the value chosen by the user
    }
}

1) 覆盖 JTable

中的方法 public TableCellEditor getCellEditor(int row, int column)
public TableCellEditor getCellEditor(int row, int column) {
    PropertiesTableModel model = (PropertiesTableModel) getModel();
    List<Object> values = model.getPossibleValues(row, column);
    if (values != null) {
       return new DefaultCellEditor(new JComboBox(values.toArray()));
    } else {
       return super.getCellEditor(row, column);
    }
}

2) 您可以创建自定义编辑器,根据当前编辑的单元格将所有调用委托给两个(或更多)编辑器之一。

public class CellEditorMulticaster implements TableCellEditor {
    private DefaultTableCellEditor textEditor;
    private DefaultTableCellEditor currentEditor;

    public CellEditorMulticaster() {
        firstEditor = new DefaultTableCellEditor(new JTextField());
    }

    Component getTableCellEditorComponent(JTable table, Object value,
                                      boolean isSelected,
                                      int row, int column) {
        PropertiesTableModel model = (PropertiesTableModel) table.getModel();
        List<Object> values = model.getPossibleValues(row, column);
        if (values != null) {
            currentEditor = new DefaultCellEditor(new JComboBox(values.toArray()));
        } else {
            currentEditor = textEditor;
        }
        return currentEditor.getTableCellEditorComponent(table, value,
               isSelected, row, column);
    }

    public Object getCellEditorValue() {
        return currentEditor.getCellEditorValue();
    }

    public boolean isCellEditable(EventObject anEvent) {
        JTable table = (JTable) anEvent.getSource;
        int row, col;
        if (anEvent instanceof MouseEvent) {
            MouseEvent evt = (MouseEvent) anEvent;
            row = table.rowAtPoint(evt.getPoint());
            col = table.columnAtPoint(evt.getPoint());
        } else {
            row = table.getSelectedRow();
            col = table.getSelectedColumn();
        }
        PropertiesTableModel model = (PropertiesTableModel) table.getModel();
        List<Object> values = model.getPossibleValues(row, column);
        if (values != null) {
            return true;
        } else {
            return textEditor.isCellEditable(anEvent);
        }
    }

    public boolean shouldSelectCell(EventObject anEvent) {
        return true;
    }

    public boolean stopCellEditing() {
        return currentEditor.stopCellEditing();
    }

    public void  cancelCellEditing() {
        currentEditor.cancelCellEditing();
    }

    // same pattern for another methods (delegate to currentEditor)
}   

很抱歉,我无法添加评论,但我必须向 sergiy 的回答报告问题。

它用于第 1 步:1) 在 JTable

中覆盖方法 public TableCellEditor getCellEditor(int row, int column)

我发现每次单击组合框时,此代码都会创建一个新的组合框作为新的单元格编辑器。我的代码将在我点击 2-3 次后崩溃,因为索引超出了长度范围。

我对此一头雾水,希望能在这里得到答案。

我的代码是:

@Override
    public TableCellEditor getCellEditor(int row, int column) {
        TableModel model = (TableModel) getModel();
        String[] values = model.getPossibleValues(row, column);
        if (values != null) {
            JComboBox<String> comboBox = new JComboBox<String>(values);
            comboBox.addActionListener((e)->{
                model.setValueAt(row, column, comboBox.getSelectedItem());
            });
            return new DefaultCellEditor(comboBox);
        } else {
            return super.getCellEditor(row, column);            
        }
    }