I've created a custom combo box that displays possible changes in state for orders. I did it with the help of this post, using MadProgrammer's code as base line:
Changing Dropdown content in a JTable Column in Swing
It worked, partially. Even though after clicking the combo box is activated and it shows the proper state options for the user, it has the following problem.
After the user selects the option, the combo box doesn't set the selected value in the table. However if the user changes the combo box of another order, the change does take place. It also works if you click other part of the selected row that isn't the combo box cell.
I suspect that this is because the cell only changes to be a combo box when is clicked, so it doesn't behave like a combo box does. Yet I'm a bit lost in how to fix it.
Any help is greatly appreciated.
Here are the relevant parts of my code:
EDIT: Following Andrew Thompson's advice, i replaced the code with a reproducible example. I'll be working on MadProgrammer's suggested solution and update it later.
package test;
import java.awt.Component;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
public class TestCellEditor {
public static void main(String[] args) {
new TestCellEditor();
}
public TestCellEditor() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
List<String> values = new ArrayList<>(5);
values.add("B");
values.add("A");
values.add("O");
values.add("G");
values.add("P");
ComboBoxTableCellEditor editor = new ComboBoxTableCellEditor(values);
DefaultTableModel model = new DefaultTableModel(new Object[]{"Status"}, 5);
JTable table = new JTable(model);
table.getColumnModel().getColumn(0).setCellEditor(editor);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ComboBoxTableCellEditor extends AbstractCellEditor implements TableCellEditor {
private JComboBox editor;
private List<String> masterValues;
public ComboBoxTableCellEditor(List<String> masterValues) {
this.editor = new JComboBox();
this.masterValues = masterValues;
}
@Override
public Object getCellEditorValue() {
return editor.getSelectedItem();
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
DefaultComboBoxModel model = new DefaultComboBoxModel(masterValues.toArray(new String[masterValues.size()]));
for (int index = 0; index < table.getRowCount(); index++) {
}
editor.setModel(model);
editor.setSelectedItem(value);
return editor;
}
}
}
This approach will only override the getTableCellEditorComponent(...)
method of the DefaultCellEditor to reset the model of the combo box based on a value in the current row that is being edited.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class StateCellEditor extends DefaultCellEditor
{
private int lookupColumn;
private HashMap<Object, DefaultComboBoxModel<?>> map;
public StateCellEditor(JComboBox<?> comboBox, int lookColumn, HashMap<Object, DefaultComboBoxModel<?>> map)
{
super(comboBox);
this.lookupColumn = lookupColumn;
this.map = map;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
{
Component c = super.getTableCellEditorComponent(table, value, isSelected, row, column);
JComboBox<?> comboBox = (JComboBox<?>)c;
Object lookup = table.getModel().getValueAt(row, lookupColumn);
DefaultComboBoxModel model = map.get( lookup );
comboBox.setModel( model );
return comboBox;
}
private static void createAndShowUI()
{
HashMap<Object, DefaultComboBoxModel<?>> map = new HashMap<>();
map.put("Color", new DefaultComboBoxModel<Object>( new String[]{ "Red", "Blue", "Green" } ));
map.put("Shape", new DefaultComboBoxModel<Object>( new String[]{ "Circle", "Square", "Triangle" } ));
map.put("Fruit", new DefaultComboBoxModel<Object>( new String[]{ "Apple", "Orange", "Banana" } ));
JPanel panel = new JPanel( new BorderLayout() );
panel.setLayout( new BorderLayout() );
// Create the table with default data
Object[][] data =
{
{"Color", "Red"},
{"Shape", "Square"},
{"Fruit", "Banana"}
};
String[] columnNames = {"Type","Value"};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
JTable table = new JTable(model);
DefaultCellEditor dce = new StateCellEditor(new JComboBox<Object>(), 0, map);
table.getColumnModel().getColumn(1).setCellEditor(dce);
JScrollPane scrollPane = new JScrollPane( table );
panel.add( scrollPane );
JFrame frame = new JFrame("Table Combo Box by Row");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel, BorderLayout.CENTER);
frame.setSize(200, 200);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}