Search code examples
javaswingjtablejcheckboxtablecellrenderer

Checkboxes in a JTabel column instead of boolean values using CellRenderer


I am adding a cell renderer to one of my column. Which is intended to return checkbox instead of boolean values. By doing below stuff I can able to get the checkboxes on passing boolean values but I am unable to check/uncheck the boxes.

It works fine if I override the getColumnClass() of DataTableModel.

But I need it with renderers

public class CustomRenderer
{
Table table = new JTable();
public DefaultTableModel getDtmInsurance()
{
    if (dtmInsurance == null)
    {
        String[] columns = { "LIC ID", "Delete" };
        dtmInsurance = new DefaultTableModel(columns, 0)
        {
            private static final long   serialVersionUID    = 1L;

            @Override
            public boolean isCellEditable(int row, int column)
            {
                if (column == 1)
                    return true;
                return false;
            }
        };
        dtmInsurance.setColumnIdentifiers(columns);
        table.setModel(dtmInsurance);
        Object[] addInsurance = { "0", false };
        dtmInsurance.addRow(addInsurance);
    }
    table.getColumnModel().getColumn(1).setCellRenderer(new MyRenderer());

    return dtmInsurance;
}

class MyRenderer extends DefaultTableCellRenderer
{
    private static final long   serialVersionUID    = 1L;

    JCheckBox                   check               = new JCheckBox();

    public Component getTableCellRendererComponent(JTable table, Object obj, boolean isSelected, boolean hasFocus, int row, int column)
    {
        Component cell = super.getTableCellRendererComponent(table, obj, isSelected, hasFocus, row, column);
        if (obj instanceof Boolean)
        {
            return check;
        }
        return cell;
    }
}
}

Solution

  • Now, you could go through the exercise of implementating your own renderer and editor OR you could let the table API do it for you.

    You could just add

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        Class type = String.class;
        switch (columnIndex) {
            case 0:
                type = Integer.class;
                break;
            case 1:
                type = Boolean.class;
                break;
        }
        return type;
    }
    

    To your dtmInsurance implementation and get

    NotSelectedSelected

    for free.

    Otherwise you should have a look at Concepts: Editors and Renderers and Using Other Editors for more details about making it yourself :P

    A custom editor might look something like...

    public class MyBooleanEditor extends AbstractCellEditor implements TableCellEditor {
    
        private JCheckBox check = new JCheckBox();
    
        @Override
        public Object getCellEditorValue() {
            return check.isSelected();
        }
    
        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            if (value instanceof Boolean) {
                check.setSelected((Boolean)value);
            }
            return check;
        }
    }
    

    Which you would be able to use similarly to...

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.EventQueue;
    import javax.swing.AbstractCellEditor;
    import javax.swing.JCheckBox;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.table.DefaultTableCellRenderer;
    import javax.swing.table.DefaultTableModel;
    import javax.swing.table.TableCellEditor;
    import javax.swing.table.TableColumn;
    
    public class CustomRenderer extends JPanel {
    
        private JTable table = new JTable();
        private DefaultTableModel dtmInsurance;
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new CustomRenderer());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public CustomRenderer() {
            setLayout(new BorderLayout());
            table.setModel(getDtmInsurance());
            TableColumn column = table.getColumnModel().getColumn(1);
            column.setCellEditor(new MyBooleanEditor());
            column.setCellRenderer(new MyBooleanRenderer());
            add(new JScrollPane(table));
        }
    
        public DefaultTableModel getDtmInsurance() {
            if (dtmInsurance == null) {
                String[] columns = {"LIC ID", "Delete"};
                dtmInsurance = new DefaultTableModel(columns, 0) {
                    private static final long serialVersionUID = 1L;
    
                    @Override
                    public boolean isCellEditable(int row, int column) {
                        if (column == 1) {
                            return true;
                        }
                        return false;
                    }
                };
                dtmInsurance.setColumnIdentifiers(columns);
                table.setModel(dtmInsurance);
                Object[] addInsurance = {"0", false};
                dtmInsurance.addRow(addInsurance);
            }
    
            return dtmInsurance;
        }
    
        class MyBooleanRenderer extends DefaultTableCellRenderer {
    
            private static final long serialVersionUID = 1L;
    
            JCheckBox check = new JCheckBox();
    
            @Override
            public Component getTableCellRendererComponent(JTable table, Object obj, boolean isSelected, boolean hasFocus, int row, int column) {
                Component cell = super.getTableCellRendererComponent(table, obj, isSelected, hasFocus, row, column);
                if (obj instanceof Boolean) {
                    return check;
                }
                return cell;
            }
        }
    
        public class MyBooleanEditor extends AbstractCellEditor implements TableCellEditor {
    
            private JCheckBox check = new JCheckBox();
    
            @Override
            public Object getCellEditorValue() {
                return check.isSelected();
            }
    
            @Override
            public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
                if (value instanceof Boolean) {
                    check.setSelected((Boolean)value);
                }
                return check;
            }
        }
    }
    

    But if I have 10 rows in my table, the checkbox which i selected first as soon as starting the program, only for that checkbox I can able to check/uncheck. Not for all

    You cell renderer doesn't update the state of the checkbox each time it's called, it's just return a empty checkbox.

    Something more like...

    class MyBooleanRenderer implements TableCellRenderer {
    
        private static final long serialVersionUID = 1L;
    
        JCheckBox check = new JCheckBox();
    
        @Override
        public Component getTableCellRendererComponent(JTable table, Object obj, boolean isSelected, boolean hasFocus, int row, int column) {
            check.setSelected(false);
            if (obj instanceof Boolean) {
                check.setSelected((Boolean)obj);
            }
            if (isSelected) {
                check.setForeground(table.getSelectionForeground());
                check.setBackground(table.getSelectionBackground());
            } else {
                check.setForeground(table.getForeground());
                check.setBackground(table.getBackground());
            }
            return check;
        }
    }
    

    Seems to work