0

not sure if someone can help me out. I'm trying to create a JTable in my program having JComboBoxes in each cell of a specified column.

In order to make this possible I extended the DefaultTableCellRender and the AbstractCellEditor. Everything is working fine so far. I get already a JComboBox shown when I do a click on one of the cells that should contain a JComboBox. But the problem is as follows:

Once I select an item in the combo box and select another row of my table, the item I selected in one combo box gets selected in every combo box of the entire column and therefore the same value is shown in every cell of my combo-box-column.

I wrote the cell renderer and the cell editor according to the following tutorial: http://www.codejava.net/java-se/swing/how-to-create-jcombobox-cell-editor-for-jtable

This is my table model:

public class FeuhermanMitgliederReportTableModel extends AbstractTableModel {
/**
 * 
 */
private static final long serialVersionUID = 1L;
private FeuhermanTabIdentifications identification;
private Object[][] extendedMitgliederList = null;

protected FeuhermanController controller = null;

/**
 * 
 */
public FeuhermanMitgliederReportTableModel(FeuhermanTabIdentifications _identification) {
    // TODO Auto-generated constructor stub
    identification = _identification;
    controller = new FeuhermanController();
    ArrayList<Mitglieder> mitgliederList = controller.getMitglieder();

    switch (identification) {
        case UEBUNG:
            extendedMitgliederList = new Object[mitgliederList.size()][4];

            for (Mitglieder m : mitgliederList) {
                int mIndex = mitgliederList.indexOf(m);
                extendedMitgliederList[mIndex][0] = new Boolean(false);
                extendedMitgliederList[mIndex][1] = m;
                extendedMitgliederList[mIndex][2] = new Boolean(false);
                extendedMitgliederList[mIndex][3] = null;
            }
            break;
        case TAETIGKEIT:
            extendedMitgliederList = new Object[mitgliederList.size()][2];

            for (Mitglieder m : mitgliederList) {
                int mIndex = mitgliederList.indexOf(m);
                extendedMitgliederList[mIndex][0] = new Boolean(false);
                extendedMitgliederList[mIndex][1] = m;
            }
            break;
        default:
            extendedMitgliederList = null;
            break;
    }
}

/* (non-Javadoc)
 * @see javax.swing.table.TableModel#getRowCount()
 */
@Override
public int getRowCount() {
    // TODO Auto-generated method stub
    return extendedMitgliederList.length;
}

/* (non-Javadoc)
 * @see javax.swing.table.TableModel#getColumnCount()
 */
@Override
public int getColumnCount() {
    // TODO Auto-generated method stub
    int retVal = 0;

    switch (identification) {
        case UEBUNG:
            retVal = 5;
            break;
        case TAETIGKEIT:
            retVal = 3;
            break;
        default:
            retVal = 0;
            break;
    }

    return retVal;
}

@Override
public String getColumnName(int column) {
    // TODO Auto-generated method stub
    String[] columnNames = null;

    switch (identification) {
        case UEBUNG:
            columnNames = new String[] {"Eingesetzt","Passnummer", "Name","ATS","KF"};
            break;
        case TAETIGKEIT:
            columnNames = new String[] {"Eingesetzt","Passnummer", "Name"};
            break;
        default:
            columnNames = null;
            break;
    }

    return columnNames[column];
}

@Override
public Class<?> getColumnClass(int columnIndex) {
    // TODO Auto-generated method stub
    Class<?> retVal = null;

    switch (columnIndex) {
    case 0:
        retVal = Boolean.class;
        break;
    case 1:
        retVal = Integer.class;
        break;
    case 2:
        retVal = String.class;
        break;
    case 3:
        retVal = Boolean.class;
        break;
    case 4:
        retVal = FahrzeugeGeraete.class;
        break;

    default:
        retVal = this.getValueAt(0, columnIndex).getClass();
        break;
    }

    return retVal;
}

/* (non-Javadoc)
 * @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int, int)
 */
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    // TODO Auto-generated method stub
    if (columnIndex == 0) {
        extendedMitgliederList[rowIndex][0] = (Boolean) aValue;
    } else if (columnIndex == 3) {
        extendedMitgliederList[rowIndex][2] = (Boolean) aValue;
        if (!(Boolean)this.getValueAt(rowIndex, 0) && (Boolean) aValue) {
            this.setValueAt(aValue, rowIndex, 0);
            this.fireTableDataChanged();
        }
    } else if (columnIndex == 4) {
        extendedMitgliederList[rowIndex][3] = (FahrzeugeGeraete) aValue;
    }

    super.setValueAt(aValue, rowIndex, columnIndex);
}

/* (non-Javadoc)
 * @see javax.swing.table.TableModel#getValueAt(int, int)
 */
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
    // TODO Auto-generated method stub
    Object[] extendedM = extendedMitgliederList[rowIndex];
    Object[] values = null;

    switch (identification) {
        case UEBUNG:
            values = new Object[] {(Boolean)extendedM[0], ((Mitglieder)extendedM[1]).getMPassnr(), ((Mitglieder)extendedM[1]).getMName() + " " + ((Mitglieder)extendedM[1]).getMVorname(), (Boolean)extendedM[2], extendedM[3]};
            break;
        case TAETIGKEIT:
            values = new Object[] {(Boolean)extendedM[0], ((Mitglieder)extendedM[1]).getMPassnr(), ((Mitglieder)extendedM[1]).getMName() + " " + ((Mitglieder)extendedM[1]).getMVorname()};
            break;
        default:
            values = null;
            break;
    }

    return values[columnIndex];
}

public Object[] getRowAt(int rowIndex) {
    return extendedMitgliederList[rowIndex];
}

/* (non-Javadoc)
 * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int)
 */
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
    // TODO Auto-generated method stub
    return (columnIndex == 0  || columnIndex == 3 || columnIndex == 4)?true:super.isCellEditable(rowIndex, columnIndex);
}

/* (non-Javadoc)
 * @see javax.swing.table.AbstractTableModel#fireTableDataChanged()
 */
@Override
public void fireTableDataChanged() {
    // TODO Auto-generated method stub
    super.fireTableDataChanged();
}

/*public Object[] getRowByPassNr(int passNr) {
    Object[] retVal = null;

    for (Object[] m : extendedMitgliederList) {
        if (((Mitglieder)m[1]).getMPassnr() == passNr)
            retVal = m;
    }

    return retVal;
}*/

public void setCheckBoxByPassNr(int passNr) {
    for (Object[] m : extendedMitgliederList) {
        if (((Mitglieder)m[1]).getMPassnr() == passNr)
            m[0] = true;
    }

    this.fireTableDataChanged();
}
}

My cell renderer:

public class FeuhermanKFCellRenderer extends DefaultTableCellRenderer {

public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {
    if (value instanceof FahrzeugeGeraete) {
        this.setText(((FahrzeugeGeraete)value).getFzgBezeichnung());
    }

    if (isSelected) {
        setBackground(table.getSelectionBackground());
    } else {
        setBackground(table.getSelectionForeground());
    }

    return this;
}
}

My cell editor:

public class FeuhermanKFCellEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {

private FahrzeugeGeraete fzg = null;
private ArrayList<FahrzeugeGeraete> content = null;

protected FeuhermanController controller = null;

public FeuhermanKFCellEditor() {
    // TODO Auto-generated constructor stub
    this.controller = new FeuhermanController();
    this.content = this.controller.getFahrzeugeGeraete(2);
}

@Override
public Object getCellEditorValue() {
    // TODO Auto-generated method stub
    return this.fzg;
}

@Override
public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub
    JComboBox<FahrzeugeGeraete> cbKF = (JComboBox<FahrzeugeGeraete>) e.getSource();
    this.fzg = (FahrzeugeGeraete) cbKF.getSelectedItem();
}

@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
    // TODO Auto-generated method stub
    if (value instanceof FahrzeugeGeraete) {
        this.fzg = (FahrzeugeGeraete) value;
    }

    JComboBox<FahrzeugeGeraete> cbKF = new JComboBox<FahrzeugeGeraete>();

    for (FahrzeugeGeraete tempFzg : content) {
        cbKF.addItem(tempFzg);
    }

    cbKF.setSelectedItem(fzg);
    cbKF.addActionListener(this);

    if (isSelected) {
        cbKF.setBackground(table.getSelectionBackground());
    } else {
        cbKF.setBackground(table.getSelectionForeground());
    }

    return cbKF;
}
}

Where the table is created:

tabMitglieder = new JTable(new FeuhermanMitgliederReportTableModel(FeuhermanTabIdentifications.UEBUNG)) {
        public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
        {
            Component c = super.prepareRenderer(renderer, row, column);

            if (!isRowSelected(row) && !(Boolean)tabMitglieder.getValueAt(row, 0)) {
                //c.setBackground(row % 2 == 0 ? new Color(200,0,0) : Color.RED);
                c.setBackground(new Color(200,0,0));
                c.setForeground(Color.WHITE);
            }

            if(!isRowSelected(row) && (Boolean)tabMitglieder.getValueAt(row, 0)) {
                //c.setBackground(row % 2 == 0 ? new Color(0,200,0) : Color.GREEN);
                c.setBackground(new Color(0,200,0));
                c.setForeground(new Color(0,80,0));
            }

            return c;
        }
    };
    tabMitglieder.setDefaultRenderer(FahrzeugeGeraete.class, new FeuhermanKFCellRenderer());
    tabMitglieder.setDefaultEditor(FahrzeugeGeraete.class, new FeuhermanKFCellEditor());
    tabMitglieder.setFillsViewportHeight(true);
    tabMitglieder.setFont(new Font("SansSerif", tabMitglieder.getFont().getStyle(), 18));
    tabMitglieder.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    tabMitglieder.setRowHeight(tabMitglieder.getFont().getSize() + 5);

I've already spend hours of searching the internet but unfortunately I couldn't find the solution for my problem.

I would appreciate it if someone could help me get this thing working.

Many thanks in advance!

Cheers, Andi

  • I would guess your combo box editor is not creating a new instance of the Object that is added to the TableModel each time an item is selected. Therefore the item becomes shared by every row. I don't see any reason for using a custom renderer/editor. Just use the default renderer/editor then you don't need to worry about this. See the section from the Swing tutorial on [Using a Combo Box as an Editor](http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#combobox). – camickr May 02 '16 at 21:28
  • I think the problem is in your CellEditor, `this.fzg` is only set when value is given. It's not set to `null` or any other value when value is null or not instanceof FahrzeugeGeraete. So it will always show the old value when new selected row's value is null or not instanceof .... Further: You should not create new instances of ComboBoxes (or any other components) in CellRenderer and/or CellEditor. You should re-use them once created. – Ben May 02 '16 at 21:56
  • A similar issue is examined [here](http://stackoverflow.com/q/36778329/230513). – trashgod May 02 '16 at 22:24
  • Thanks a lot for your input guys! I could solve it now by changing the renderer and the editor in a way that `this.fzg` is also set when `value` is `null` or not `instance of FahrzeugeGeraete`. – Andreas Krassnig May 05 '16 at 21:21

0 Answers0