Dan Dan - 18 days ago 12
Java Question

Background color flickers using JCheckBox in JTable

On my

JTable
, I am setting the background colors of the rows using the
prepareRenderer
function. I also removed the focus border and later in the code I disable the row selection.

JTable table = new JTable() {
private static final long serialVersionUID = -2965586838134675413L;
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
c.setBackground(row % 2 == 1 ? Color.WHITE : new Color(255, 245, 248));
((JComponent) c).setBorder(null);
return c;
}
};

DefaultTableModel tableModel = new DefaultTableModel(sampleData, headers) {
private static final long serialVersionUID = 9186050244728809804L;

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


@Override
public boolean isCellEditable(int row, int column) {
switch(column) {
case 0:
return true;
default:
return false;
}
}

@SuppressWarnings("unchecked")
@Override
public void setValueAt(Object aValue, int row, int column) {
if (aValue instanceof Boolean && column == 0) {
//System.out.println(aValue);
Vector<Boolean> rowData = (Vector<Boolean>) getDataVector().get(row);
rowData.set(0, (boolean) aValue);
fireTableCellUpdated(row, column);
}
}
};

table.setModel(tableModel);
table.setRowSelectionAllowed(false);


The problem is when I click on the
JCheckBox
es in the background color switches to white while the mouse button pressed down. Is there a way keep to keep the color from changing whilst clicking on the
JCheckBox
?

Note

Using the default boolean renderer to achieve this still has the same problem but it does not happen as often

private class BooleanRenderer extends JCheckBox implements TableCellRenderer
{
private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);

public BooleanRenderer() {
super();
setHorizontalAlignment(JLabel.CENTER);
setBorderPainted(true);
}

public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setSelected((value != null && ((Boolean)value).booleanValue()));
setBorder(noFocusBorder);

return this;
}
}

table.setDefaultRenderer(Boolean.class, new BooleanRenderer())


Note 2

I also tried adding a
MouseListener
to the
JCheckBox
but that did not work as the mouse listener did not seem to attach to the
JCheckBox


JTable fileList = new JTable() {
private static final long serialVersionUID = -2965586838134675413L;
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
c.setBackground(row % 2 == 1 ? Color.WHITE : new Color(255, 245, 248));
((JComponent) c).setBorder(null);

if(c instanceof JCheckBox) {
c.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
setBackground(row % 2 == 1 ? Color.WHITE : new Color(255, 245, 248));
}

public void mousePressed(MouseEvent e) {
setBackground(row % 2 == 1 ? Color.WHITE : new Color(255, 245, 248));
}

public void mouseReleased(MouseEvent e) {
setBackground(row % 2 == 1 ? Color.WHITE : new Color(255, 245, 248));
}
});
}
return c;
}
};


Edit - SSSCE using first example of code

import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class JTableTest extends JFrame {
private JTableTest() {
super("Button Layout");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(1, 1));
createPanel();
pack();
setVisible(true);
}

JPanel panel = new JPanel(new GridLayout(1, 1));
JScrollPane scroll = new JScrollPane();

private void createPanel() {
Object[] headers = {"Select", "Title", "Artist", "Length"};
Object[][] sampleData = {{true, "Bat Outta Hell", "Meat Loaf", "673"},
{false, "Spanish Train", "Chris De Burgh", "358"}};
JTable table = new JTable() {
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
c.setBackground(row % 2 == 1 ? Color.WHITE : Color.RED);
((JComponent) c).setBorder(null); //Left in so it is easier to see problem
return c;
}
};

DefaultTableModel tableModel = new DefaultTableModel(sampleData, headers) {
@Override
public Class<?> getColumnClass(int columnIndex) {
switch(columnIndex) {
case 0:
return Boolean.class;
default:
return String.class;
}
}
};

table.setModel(tableModel);
table.setRowSelectionAllowed(false); //Left in so it is easier to see problem

scroll.getViewport().add(table);
panel.add(scroll);
getContentPane().add(panel);
}

public static void main(String[] args) {
new JTableTest();
}
}

TT. TT.
Answer

You are missing a prepareEditor override in your JTable instance, I added one in your sample. When you click on the checkbox, what is displayed is the editor component rather than the renderer component. You need to prepare that component as well to get the coloring you want.

import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

@SuppressWarnings("serial")
public class JTableTest extends JFrame {
    private JTableTest()  {
        super("Button Layout");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new GridLayout(1, 1));
        createPanel();
        pack();
        setVisible(true);
    }

    JPanel panel = new JPanel(new GridLayout(1, 1));
    JScrollPane scroll = new JScrollPane();

    private void createPanel() {
        Object[] headers = {"Select", "Title", "Artist", "Length"};
        Object[][] sampleData = {{true, "Bat Outta Hell", "Meat Loaf", "673"},
                {false, "Spanish Train", "Chris De Burgh", "358"}};
        JTable table = new JTable() {
            public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
                Component c = super.prepareRenderer(renderer, row, column);
                c.setBackground(row % 2 == 1 ? Color.WHITE : Color.RED);
                ((JComponent) c).setBorder(null); //Left in so it is easier to see problem
                return c;
            }

            @Override
            public Component prepareEditor(TableCellEditor editor, int row, int column) {
                Component c = super.prepareEditor(editor, row, column);
                c.setBackground(row % 2 == 1 ? Color.WHITE : Color.RED);
                ((JComponent) c).setBorder(null); //Left in so it is easier to see problem
                return c;
            }
        };

        DefaultTableModel tableModel = new DefaultTableModel(sampleData, headers) {
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                switch(columnIndex) {
                    case 0:
                        return Boolean.class;
                    default:
                        return String.class;
                }
            }
        };

        table.setModel(tableModel);
        table.setRowSelectionAllowed(false); //Left in so it is easier to see problem

        scroll.getViewport().add(table);
        panel.add(scroll);
        getContentPane().add(panel);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater (
            new Runnable() {
                @Override
                public void run() {
                    new JTableTest();
                }
            }
        );
    }
}