Question

I created JTable that contains information about employees. In this JTable I added the column called "Qualifications". This column is represented by JComboBox (different content at each row). For instance:

Row 1 |  JComboBox(){"Programmer","Web"}
Row 2 |  JComboBox(){"Writer","Editor"}

The JComboBox content is taken from the List<String> employees[row].getQualification().

The problem is that the selected item in Row 1 and Row 2 is "Programmer", however "Programmer" should not appear in Row 2. Only when I click on JComboBox, the correct list appears, i.e. Row 2 - {"Writer","Editor"}.

    TableColumn column = table.getColumnModel().getColumn(5);
    column.setCellRenderer(getRenderer());

    private TableCellRenderer getRenderer() {
    return new TableCellRenderer() {

        private JComboBox<String> box = new JComboBox<String>();
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {            
            for (String q : employees[row].getQualification())
                box.addItem(q);
            box.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
            box.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
            return box;
           }
        };
    }
Was it helpful?

Solution

Override the getCellEditor() method of the JTable. Something like:

import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;

public class TableComboBoxByRow extends JPanel
{
    List<TableCellEditor> editors = new ArrayList<TableCellEditor>(3);

    public TableComboBoxByRow()
    {
        setLayout( new BorderLayout() );

        // Create the editors to be used for each row

        String[] items1 = { "Red", "Blue", "Green" };
        JComboBox<String> comboBox1 = new JComboBox<String>( items1 );
        DefaultCellEditor dce1 = new DefaultCellEditor( comboBox1 );
        editors.add( dce1 );

        String[] items2 = { "Circle", "Square", "Triangle" };
        JComboBox<String> comboBox2 = new JComboBox<String>( items2 );
        DefaultCellEditor dce2 = new DefaultCellEditor( comboBox2 );
        editors.add( dce2 );

        String[] items3 = { "Apple", "Orange", "Banana" };
        JComboBox<String> comboBox3 = new JComboBox<String>( items3 );
        DefaultCellEditor dce3 = new DefaultCellEditor( comboBox3 );
        editors.add( dce3 );

        //  Create the table with default data

        Object[][] data =
        {
            {"Color", "Red"},
            {"Shape", "Square"},
            {"Fruit", "Banana"},
            {"Plain", "Text"}
        };
        String[] columnNames = {"Type","Value"};
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        JTable table = new JTable(model)
        {
            //  Determine editor to be used by row
            public TableCellEditor getCellEditor(int row, int column)
            {
                int modelColumn = convertColumnIndexToModel( column );

                if (modelColumn == 1 && row < 3)
                    return editors.get(row);
                else
                    return super.getCellEditor(row, column);
            }
        };

        JScrollPane scrollPane = new JScrollPane( table );
        add( scrollPane );
    }

    private static void createAndShowUI()
    {
        JFrame frame = new JFrame("Table Combo Box by Row");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new TableComboBoxByRow() );
        frame.setSize(200, 200);
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

OTHER TIPS

JComboBox-es appear only on a click

because you use them as CellEditor, which apper only when you edit cells. If you want to display your column cells as JComboBox everytime, you need to use TableCellRenderer, read about that. Here is simple example of JComboBox as renderer :

import java.awt.Component;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

public class TestFrame extends JFrame{

    public TestFrame(){
        init();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }

    private void init() {
        JTable t = new JTable(3,3);
        TableColumn column = t.getColumnModel().getColumn(2);
        column.setCellRenderer(getRenderer());
        add(new JScrollPane(t));
    }

    private TableCellRenderer getRenderer() {
        return new TableCellRenderer() {

            private JComboBox<String> box = new JComboBox<String>(new String[]{"1","2"});
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                    boolean isSelected, boolean hasFocus, int row, int column) {
                box.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
                box.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
                return box;
            }
        };
    }

    public static void main(String... s){
        new TestFrame();
    }

}

enter image description here

Thanks to @alex2410, I cleaned up the code and wrapped it into a ComboTable class which should do the job for you. instantiate ComboTable class with a hashmap of each row values (the demo assumes 2 columns, but you can add more). Note MyMap.of is just a wrapper for java 9 Map.of since I was using Java 8 at that time. same for MyList.of

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.EventObject;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

import rs.code.utils.MyList;
import rs.code.utils.MyMap;

public class Test extends JFrame
{
    private static final long serialVersionUID = 1L;
    public ComboTable table = new ComboTable(MyMap.of("Gender", MyList.of("male", "female"), "City", MyList.of("london", "bedord"), "orientation", MyList.of("left", "right")));
    public Test()
    {
        super("EachRow Editor Example");
        JScrollPane scroll = new JScrollPane(table);
        getContentPane().add(scroll, BorderLayout.CENTER);
        setPreferredSize(new Dimension(400, 120));
        setLocation(150, 100);
        pack();
        setVisible(true);

    }

    public static void main(String[] args)
    {
        Test frame = new Test();
        frame.addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowClosing(WindowEvent e)
            {
                System.out.println(frame.table.getSelectedValues().toString());
                System.exit(0);
            }
        });
    }
}

class ComboTable extends JTable
{
    private static final long serialVersionUID = 1L;
    protected Map<Integer, ComboCellEditor> editors = new LinkedHashMap<>();

    public ComboTable(Map<String, List<String>> rows)
    {
        setModel(new DefaultTableModel(new String[] {"Attribute", "Value"}, rows.size()));
        setRowHeight(20);
        EachRowEditor rowEditor = new EachRowEditor(this);
        int i = 0;
        for(String key : rows.keySet())
        {
            getModel().setValueAt(key, i, 0);
            editors.put(i++, new ComboCellEditor(createComboBox(rows.get(key))));
        }

        getColumn("Value").setCellEditor(rowEditor);
        getColumn("Value").setCellRenderer(getRenderer());
    }

    public Map<Integer, ComboCellEditor> getEditors()
    {
        return editors;
    }

    public Map<String, String> getSelectedValues()
    {
        Map<String, String> values = new LinkedHashMap<>();
        for(int i=0;i<getModel().getRowCount();i++)
        {
            values.put(getModel().getValueAt(i, 0).toString(), editors.get(i).getComboBox().getSelectedItem().toString());
        }
        return values;
    }

    private JComboBox<String> createComboBox(List<String> elements)
    {
        JComboBox<String> comboBox = new JComboBox<>();
        for (String element : elements)
        {
            comboBox.addItem(element);
        }
        comboBox.setSelectedIndex(0);
        comboBox.addComponentListener(new ComponentAdapter()
        {
            @Override
            public void componentShown(ComponentEvent e)
            {
                final JComponent c = (JComponent) e.getSource();
                SwingUtilities.invokeLater(new Runnable()
                {
                    @SuppressWarnings("rawtypes")
                    @Override
                    public void run()
                    {
                        c.requestFocus();
                        System.out.println(c);
                        if (c instanceof JComboBox)
                        {
                            System.out.println(((JComboBox) c).getSelectedItem());
                        }
                    }
                });
            }
        });

        return comboBox;
    }

    private TableCellRenderer getRenderer()
    {
        return new TableCellRenderer()
        {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
            {
                editors.get(row).getComboBox().setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
                editors.get(row).getComboBox().setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
                return editors.get(row).getComboBox();
            }
        };
    }
}

class ComboCellEditor extends DefaultCellEditor
{
    private static final long serialVersionUID = 1L;
    private final JComboBox<String> comboBox;

    public ComboCellEditor(JComboBox<String> comboBox)
    {
        super(comboBox);
        this.comboBox = comboBox;
    }

    public JComboBox<String> getComboBox()
    {
        return comboBox;
    }
}

class EachRowEditor implements TableCellEditor
{
    private TableCellEditor editor;
    private final TableCellEditor defaultEditor;
    private final ComboTable table;

    public EachRowEditor(ComboTable table)
    {
        this.table = table;
        defaultEditor = new DefaultCellEditor(new JTextField());

    }

    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
    {
        return editor.getTableCellEditorComponent(table, value, isSelected, row, column);
    }

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

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

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

    public boolean isCellEditable(EventObject anEvent)
    {
        selectEditor((MouseEvent) anEvent);
        return editor.isCellEditable(anEvent);
    }

    public void addCellEditorListener(CellEditorListener l)
    {
        editor.addCellEditorListener(l);
    }

    public void removeCellEditorListener(CellEditorListener l)
    {
        editor.removeCellEditorListener(l);
    }

    public boolean shouldSelectCell(EventObject anEvent)
    {
        selectEditor((MouseEvent) anEvent);
        return editor.shouldSelectCell(anEvent);
    }

    protected void selectEditor(MouseEvent e)
    {
        int row;
        if (e == null)
        {
            row = table.getSelectionModel().getAnchorSelectionIndex();
        }
        else
        {
            row = table.rowAtPoint(e.getPoint());
        }
        editor = table.getEditors().get(row);
        if (editor == null)
        {
            editor = defaultEditor;
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top