Jcombobox in a Jtable Cell

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

It's really simple and can be done using two ways

First of all your model should notify editor/table that the current cell has list of values.

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) Override the method public TableCellEditor getCellEditor(int row, int column) in JTable

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) You can create a custom editor which delegates all calls to one of two (or more) editors depended on the currently edited cell.

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

JComboBox in JTable cell. Selection change affects JComboBox in other rows

  • Don't use MouseListeners to show popup menus, different OSs have different triggers for the popups, and not all are triggered by mousePressed. Instead use JComponent#setComponentPopupMenu and let the API deal with it
  • Don't modify the state of the model from an editor. This can place the model into an invalidate state and cause other side effects, like you have now. Once seems to be happening is when a new row is selected, the editor is been updated with the rows cell value, but the row selection hasn't been set, so the table still thinks the previous row is still selected. Instead, use the models setValueAt method to make decisions about what to do once the first columns value is changed.

For example...

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;

public class JComboBoxInJTable {

public static void main(String[] args) {
new JComboBoxInJTable();
}

private List<String> comboData;

public JComboBoxInJTable() {
EventQueue.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}

DefaultTableModel model = new DefaultTableModel(new Object[]{"ComboBox", "Index"}, 1) {

@Override
public void setValueAt(Object aValue, int row, int column) {
super.setValueAt(aValue, row, column);
if (column == 0) {
String value = aValue == null ? null : aValue.toString();
if (aValue == null) {
super.setValueAt(null, row, 1);
} else {
super.setValueAt(comboData.indexOf(aValue), row, 1);
}
}
}

};
JTable table = new JTable(model);
table.setFillsViewportHeight(true);
table.setGridColor(Color.GRAY);

//popup menu to add row
JPopupMenu popup = new JPopupMenu();
JMenuItem newRow;
newRow = new JMenuItem("New Row");
newRow.setToolTipText("Add new row.");
newRow.addActionListener((ActionEvent nr) -> {
model.addRow(new Object[]{"", ""});
});
popup.add(newRow);

table.setComponentPopupMenu(popup);

comboData = new ArrayList<>(Arrays.asList(new String[]{"Zero", "One", "Two", "Three"}));

JComboBox combo = new JComboBox(comboData.toArray(new String[comboData.size()]));
// combo.addItemListener((ItemEvent e) -> {
// if (e.getStateChange() == ItemEvent.SELECTED) {
// //sets value of cell to left of combobox to comboboxe's selected index
// System.out.println("Selected row = " + table.getSelectedRow());
// table.setValueAt(combo.getSelectedIndex(), table.getSelectedRow(), 1);
// } else {
// //do nothing...
// }
// });

DefaultCellEditor comboEditor = new DefaultCellEditor(combo);

TableColumnModel tcm = table.getColumnModel();
tcm.getColumn(0).setCellEditor(comboEditor);

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}

Action event for a combobox inserted into a JTable Cell in java swing

every time I add a new row to the table a new combobox is generated..so how can I write an action listern to them

You should NOT be using an ActionListener.

You have three options:

  1. Override the setValue(...) method of the TableModel to do your processing
  2. Add a TableModelListener to the TableModel. Then you do you processing when the TableModelEvent is generated.
  3. Use a Table Cell Listener on your table to handle the processing.


Related Topics



Leave a reply



Submit