Search code examples
javaswingjtablejcomboboxtablecellrenderer

Setting TableCellRenderer adds an empty value atop of value list of `JComboBox`


SCCEE here:

import java.awt.EventQueue;

import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;

public class TC extends JFrame{
    public TC(){
        begin();
    }
    private void begin(){
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setTitle("nothing.");
        String[] options = {"One", "Two", "Three"};
        JComboBox<String> combo = new JComboBox<>(options);
        JTable table = new JTable(new Object[2][2], new String[]{"One", "Two"});
        TableColumn col0 = table.getColumnModel().getColumn(0);
        col0.setCellEditor(new DefaultCellEditor(combo));

        class MyRender extends DefaultTableCellRenderer {
            public MyRender() {
            }
            @Override
            public void setValue(Object value) {
                if (value instanceof JComboBox) {
                    setText(((JComboBox) value).getSelectedItem().toString());
                }
            }
        }

        MyRender renderer = new MyRender();
        col0.setCellRenderer(renderer);

        JScrollPane sp = new JScrollPane(table);
        getContentPane().add(sp);

        pack();
        setVisible(true);
    }

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

            @Override
            public void run() {
                TC tc = new TC();

            }

        });
    }
}

My problem is: setting the TableCellRenderer makes the combo choose an empty option atop of all other values, without anyone telling it to do so. The empty entry comes from nowhere.

How can I make the combo select the "One" entry at first moment, instead of " "? Something I missed when implementing the custom renderer?? I followed here:

Oracle tutorial of How to Use Tables - Swing - Java SE

Also, the combo is not shown until I click it. I don't think it's the proper way to show it. I tried to follow another example here:

Show a JComboBox with custom editor and renderer, example from java2s.com

but I remain confused.


Solution

  • How can I make the combo select the "One" entry at first moment,

    This is the default behaviour. The data from the TableModel is used to select the item in the combo box when the editor is invoked.

    The section from the Swing tutorial on Using a ComboBox as an Editor contains a working example showing how to do this.

    the combo is not shown until I click it

    This is the way it is designed. The renderer displays the data normally. The editor is not displayed until the user starts editing the cell.

    If you want to give the user an indication that a combo box will be used as the editor then you need to use a custom renderer. Your attempted implementation is incorrect because you would never have a JCombobox as data in the table model.

    Check out: How to make a JComboBox table editor have the design of an ordinary JComboBox? for a couple of different implementations of a possible renderer:

    1. my example shows what using a real combo box would be like (I don't like it) and
    2. the accepted answer shows a better renderer. You might want to change the example to have a panel as the renderer with a BorderLayout. Then you add a label to the LINE_START and the icon to the LINE_END so the icon so it more resembles a combo box with the down arrow on the right.

    Edit:

    but in your link, the combobox is showing the first option

    No it isn't. Test the code again. Click on the 2nd or 3rd row to invoke the editor to see which item is selected.

    To clarify what I said earlier. The item in the combo box is selected based on the data in the TableModel. Since your TableModel is empty there is no item to select.

    Put some data in the TableModel. The example from the Swing tutorial and the two examples in the link I provided you all have data in the TableModel which is why they work.