Search code examples
javaswingjtableimageicontablecellrenderer

Highlighting row selection in JTable with custom rendering


I am creating JTable with custom table cell renderer by extending DefaultTableCellRenderer where I would like to use some image along with the text.

enter image description here

As you can see above, even though I have selected the particular row, it is not highlighting in the Testcases column. I have tried some existing SO questions (Q1, Q2) solutions, but still it is not working. Where I am making the mistake ?

JTableTest.java

import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class JTableTest extends JFrame {

    public DefaultTableModel testcaseModel;
    public JTable testcasesTable;
    Object[] testcaseTableColumns = {"S.No", "Testcases"};
    public static final int TESTCASE_SNO_COLUMN = 0;
    public static final int TESTCASE_NAME_COLUMN = 1;

    public JTableTest() {
        initComponents();
    }

    private void initComponents() {
        if (testcaseModel == null) {
            testcaseModel = new DefaultTableModel(null, testcaseTableColumns){

                @Override
                public Class<?> getColumnClass(int columnIndex) {
//                    if (columnIndex == -1) {
//                        return Integer.class;
//                    } else if(columnIndex==1){
//                        return JLabel.class;
//                    }
                    return Object.class;
                }

            };
        }
        if (testcasesTable == null) {
            testcasesTable = new JTable(testcaseModel) {
                @Override
                public boolean isCellEditable(int row, int column) {
                    return false;
                }
            };
        }
        testcasesTable.setCellSelectionEnabled(true);
        testcasesTable.getColumnModel().getColumn(TESTCASE_NAME_COLUMN).setCellRenderer(new LabelRenderer());
        for (int i = 0; i < 10; i++) {
            testcaseModel.addRow(new Object[]{i, (i * 100)});
        }
    }

    public static void main(String[] args) {
        JTableTest jTableTest = new JTableTest();
        jTableTest.setSize(300, 300);
        jTableTest.setTitle("TableIcon");
        jTableTest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel pnlMain = new JPanel(new BorderLayout(10, 10));
        JScrollPane scrollPane = new JScrollPane(jTableTest.testcasesTable);
        pnlMain.add(scrollPane);
        jTableTest.getContentPane().add(pnlMain);
        jTableTest.setVisible(true);

    }

}

LabelRenderer.java

import java.awt.Component;
import java.awt.Insets;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.table.DefaultTableCellRenderer;


public class LabelRenderer extends DefaultTableCellRenderer {

    public static final Border focusedCellBorder = UIManager.getBorder("Table.focusCellHighlightBorder");

    public static final Border unfocusedCellBorder = createEmptyBorder();

    private static Border createEmptyBorder() {
        Insets i = focusedCellBorder.getBorderInsets(new JLabel());
        return BorderFactory.createEmptyBorder(i.top, i.left, i.bottom, i.right);
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        String text = value.toString();
        JLabel label = new JLabel(text);

        try {
            label.setIcon(new ImageIcon(getClass().getResource("ok_16px.png")));
            // This below code setting the border to be highlighted, but not whole              
            label.setBorder(hasFocus ? focusedCellBorder : unfocusedCellBorder);

        } catch (Exception ex) {
            System.out.println(ex);
        }
       // This also not working.....    
        if (isSelected) {
            label.setBackground(table.getSelectionBackground());
            label.setForeground(table.getSelectionForeground());
        } else {
            label.setBackground(table.getBackground());
            label.setForeground(table.getForeground());
        }
        return label;
    }
}

Solution

  • Don't create another JLabel in the TableCellEditor, DefaultTableCellEditor extends from JLabel already, you just to apply the settings you need, leave the DefaultTableCellRenderer to take care of the rest

    Selected

    public class LabelRenderer extends DefaultTableCellRenderer {
    
        public static final Border focusedCellBorder = UIManager.getBorder("Table.focusCellHighlightBorder");
    
        public static final Border unfocusedCellBorder = createEmptyBorder();
    
        private static Border createEmptyBorder() {
            Insets i = focusedCellBorder.getBorderInsets(new JLabel());
            return BorderFactory.createEmptyBorder(i.top, i.left, i.bottom, i.right);
        }
    
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    
            String text = value.toString();
    
            try {
                setIcon(new ImageIcon(getClass().getResource("ok_16px.png")));
                // This below code setting the border to be highlighted, but not whole              
    
            } catch (Exception ex) {
                System.out.println(ex);
            }
            setBorder(hasFocus ? focusedCellBorder : unfocusedCellBorder);
    
            return this;
        }
    }
    

    Also, note, that with cellSelection enabled, you will need to click a cell in the second column to see the highlighting. Turn it off to allow for full row selection